From 1dac2dd1e59603050be44def3dbadc52248ceed3 Mon Sep 17 00:00:00 2001 From: Eduardo Menges Mattje Date: Wed, 8 Jul 2026 10:29:27 -0300 Subject: [PATCH 01/62] Fixed ASAN reports in `ipfs-pubsub` and `libp2p` --- ipfs-pubsub | 2 +- libp2p | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ipfs-pubsub b/ipfs-pubsub index cb5b7f08..c71089fc 160000 --- a/ipfs-pubsub +++ b/ipfs-pubsub @@ -1 +1 @@ -Subproject commit cb5b7f08798d78cfa230696e093c44a4ef0bd59a +Subproject commit c71089fc0f0a1676da966faefb006fb5d42e4fca diff --git a/libp2p b/libp2p index 92db7a5d..d26b61bb 160000 --- a/libp2p +++ b/libp2p @@ -1 +1 @@ -Subproject commit 92db7a5d1113b391ba29ab59d27d7a9c6d9d06ff +Subproject commit d26b61bb8fe6be1c4e4a8c16db9c1752cc7a2b78 From e7e954cee649b32f700eb4b5ff011289157a737f Mon Sep 17 00:00:00 2001 From: Eduardo Menges Mattje Date: Wed, 8 Jul 2026 16:46:13 -0300 Subject: [PATCH 02/62] Fixed `wallet-core` conflicts with OpenSSL --- wallet-core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wallet-core b/wallet-core index 4fa27369..3280e625 160000 --- a/wallet-core +++ b/wallet-core @@ -1 +1 @@ -Subproject commit 4fa27369f4a4c583060023e6cb1d2277dc7f3098 +Subproject commit 3280e6250041a58e1513b19c3958568f97b73fdd From e05ecb37811a11b6f5d90528b291dde9b3261a86 Mon Sep 17 00:00:00 2001 From: itsafuu Date: Tue, 14 Jul 2026 16:01:42 -0400 Subject: [PATCH 03/62] Thread safety changes --- ipfs-bitswap-cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipfs-bitswap-cpp b/ipfs-bitswap-cpp index 1c791cfb..d5f43b9f 160000 --- a/ipfs-bitswap-cpp +++ b/ipfs-bitswap-cpp @@ -1 +1 @@ -Subproject commit 1c791cfb21ec46db31ed317b38c4de81764d34b2 +Subproject commit d5f43b9fdc102b9731de8094cb734e3875f406e4 From 5563f2055363f4977d46b892c15c12f482d89c26 Mon Sep 17 00:00:00 2001 From: itsafuu Date: Tue, 14 Jul 2026 18:11:49 -0400 Subject: [PATCH 04/62] Handles appleclang 21+ issues --- wallet-core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wallet-core b/wallet-core index 3280e625..a1554a1e 160000 --- a/wallet-core +++ b/wallet-core @@ -1 +1 @@ -Subproject commit 3280e6250041a58e1513b19c3958568f97b73fdd +Subproject commit a1554a1e8a14587d151156edf0c0c88d6f2de27d From bb783acb13a0bbf3f158fbdd447a0756b1e2c457 Mon Sep 17 00:00:00 2001 From: itsafuu Date: Tue, 14 Jul 2026 19:30:16 -0400 Subject: [PATCH 05/62] Pin to windows 2022 --- .github/workflows/build-targets.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-targets.yml b/.github/workflows/build-targets.yml index 60bcc4f4..bcbad0fc 100644 --- a/.github/workflows/build-targets.yml +++ b/.github/workflows/build-targets.yml @@ -155,7 +155,7 @@ jobs: SH_MAC='["self-hosted","gv-OSX-Large"]' FB_LINUX='["ubuntu-latest"]' FB_LINUX_ARM='["ubuntu-24.04-arm"]' - FB_WINDOWS='["windows-latest"]' + FB_WINDOWS='["windows-2022"]' FB_MAC='["macos-latest"]' # Returns the self-hosted label array if at least one matching runner From 76030fd80c0b692b00da9dd12ca7edcdf9beb35b Mon Sep 17 00:00:00 2001 From: Eduardo Menges Mattje Date: Wed, 15 Jul 2026 10:38:17 -0300 Subject: [PATCH 06/62] Updated `ipfs-pubsub` and `libp2p` --- gnus_upnp | 2 +- ipfs-pubsub | 2 +- libp2p | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gnus_upnp b/gnus_upnp index 89a7e26f..31e86849 160000 --- a/gnus_upnp +++ b/gnus_upnp @@ -1 +1 @@ -Subproject commit 89a7e26f882f803639d9513a477706822189083d +Subproject commit 31e86849f8af1ea16d7f6aecc324930c2d690aee diff --git a/ipfs-pubsub b/ipfs-pubsub index c71089fc..801e8950 160000 --- a/ipfs-pubsub +++ b/ipfs-pubsub @@ -1 +1 @@ -Subproject commit c71089fc0f0a1676da966faefb006fb5d42e4fca +Subproject commit 801e895033fa1b1b9456112f251df333219386cc diff --git a/libp2p b/libp2p index d26b61bb..2103221f 160000 --- a/libp2p +++ b/libp2p @@ -1 +1 @@ -Subproject commit d26b61bb8fe6be1c4e4a8c16db9c1752cc7a2b78 +Subproject commit 2103221f3c3f5c1204bdbc8a3decea5ab4541565 From 58b0002b45db0d14f41d9eda8dcbe760c092cfbe Mon Sep 17 00:00:00 2001 From: Henrique A Klein Date: Thu, 16 Jul 2026 12:34:04 -0300 Subject: [PATCH 07/62] Chore: Removing spamming logs --- ipfs-bitswap-cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipfs-bitswap-cpp b/ipfs-bitswap-cpp index d5f43b9f..d308c1f6 160000 --- a/ipfs-bitswap-cpp +++ b/ipfs-bitswap-cpp @@ -1 +1 @@ -Subproject commit d5f43b9fdc102b9731de8094cb734e3875f406e4 +Subproject commit d308c1f6457356b1b926c040ff8de6083409bd8f From 5d818202e2edb262b72567a3d27efa2ae1698c87 Mon Sep 17 00:00:00 2001 From: Eduardo Menges Mattje Date: Tue, 21 Jul 2026 15:09:44 -0300 Subject: [PATCH 08/62] Fixes for Windows --- AsyncIOManager | 2 +- ipfs-pubsub | 2 +- rocksdb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/AsyncIOManager b/AsyncIOManager index 46a07b10..5c63c56e 160000 --- a/AsyncIOManager +++ b/AsyncIOManager @@ -1 +1 @@ -Subproject commit 46a07b101bc6972ee3f83227b4d58c73f1513071 +Subproject commit 5c63c56ee805b1dcb59c1404702573c8915fc55d diff --git a/ipfs-pubsub b/ipfs-pubsub index 801e8950..4e3d13f3 160000 --- a/ipfs-pubsub +++ b/ipfs-pubsub @@ -1 +1 @@ -Subproject commit 801e895033fa1b1b9456112f251df333219386cc +Subproject commit 4e3d13f34b8da8a90f857fcc57cb5078408e1388 diff --git a/rocksdb b/rocksdb index 0ed3f5f5..76faeb33 160000 --- a/rocksdb +++ b/rocksdb @@ -1 +1 @@ -Subproject commit 0ed3f5f556e2ced8222c2254a2456d62ff7c5c0e +Subproject commit 76faeb3309d2a64512749edb0fce97d5d7270d95 From eb5bc6561155de7c7f1921a63fc342e23fca0237 Mon Sep 17 00:00:00 2001 From: Eduardo Menges Mattje Date: Wed, 22 Jul 2026 14:04:29 -0300 Subject: [PATCH 09/62] Added more fixes for Windows --- AsyncIOManager | 2 +- gnus_upnp | 2 +- ipfs-pubsub | 2 +- libp2p | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/AsyncIOManager b/AsyncIOManager index 5c63c56e..2aea7454 160000 --- a/AsyncIOManager +++ b/AsyncIOManager @@ -1 +1 @@ -Subproject commit 5c63c56ee805b1dcb59c1404702573c8915fc55d +Subproject commit 2aea74540f265dc75333b43a4928c4b93ea5553e diff --git a/gnus_upnp b/gnus_upnp index 31e86849..8bb78b8f 160000 --- a/gnus_upnp +++ b/gnus_upnp @@ -1 +1 @@ -Subproject commit 31e86849f8af1ea16d7f6aecc324930c2d690aee +Subproject commit 8bb78b8fb02ba4afb504ac0414e995636b412507 diff --git a/ipfs-pubsub b/ipfs-pubsub index 4e3d13f3..16056368 160000 --- a/ipfs-pubsub +++ b/ipfs-pubsub @@ -1 +1 @@ -Subproject commit 4e3d13f34b8da8a90f857fcc57cb5078408e1388 +Subproject commit 16056368f1d6ee33aa1d389cbf2c35dd143a6beb diff --git a/libp2p b/libp2p index 2103221f..af857948 160000 --- a/libp2p +++ b/libp2p @@ -1 +1 @@ -Subproject commit 2103221f3c3f5c1204bdbc8a3decea5ab4541565 +Subproject commit af8579486005065f73b4517466d51ac6b300173e From 91a0b6cb79b00fc473b068976992d4786e1e5ec1 Mon Sep 17 00:00:00 2001 From: Eduardo Menges Mattje Date: Thu, 23 Jul 2026 21:34:55 -0300 Subject: [PATCH 10/62] Fixed assert in libp2p --- libp2p | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libp2p b/libp2p index af857948..1ae9b493 160000 --- a/libp2p +++ b/libp2p @@ -1 +1 @@ -Subproject commit af8579486005065f73b4517466d51ac6b300173e +Subproject commit 1ae9b493df08aa8c56c57698328297f1286264d0 From 0774599fdebcc55e6e9ae9a584c14b59c4ee7cd1 Mon Sep 17 00:00:00 2001 From: Eduardo Menges Mattje Date: Mon, 27 Jul 2026 12:19:32 -0300 Subject: [PATCH 11/62] Fixed MNN and `wallet-core` warnings --- MNN | 2 +- build/CommonTargets.cmake | 1 + build/OSX/CMakeLists.txt | 4 ++++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/MNN b/MNN index dc6413f8..84b4cac8 160000 --- a/MNN +++ b/MNN @@ -1 +1 @@ -Subproject commit dc6413f80024200a2830e1b455b51d7b08526ae5 +Subproject commit 84b4cac8d60633ae5ed94149732ddf814bbb2e2f diff --git a/build/CommonTargets.cmake b/build/CommonTargets.cmake index 766accc1..b57f02d4 100644 --- a/build/CommonTargets.cmake +++ b/build/CommonTargets.cmake @@ -622,6 +622,7 @@ ExternalProject_Add(wallet-core -DTW_STATIC_LIBRARY:BOOL=ON -DTW_UNIT_TESTS:BOOL=OFF -DTW_USE_EXTERNAL_PROTOC:BOOL=ON + ${_WALLET_CORE_EXTRA_CACHE_ARGS} -Dutf8_range_DIR:PATH=${utf8_range_DIR} ${_CMAKE_COMMON_CACHE_ARGS} ${_BOOST_CACHE_ARGS} diff --git a/build/OSX/CMakeLists.txt b/build/OSX/CMakeLists.txt index 821af5f1..ca828f18 100644 --- a/build/OSX/CMakeLists.txt +++ b/build/OSX/CMakeLists.txt @@ -294,4 +294,8 @@ set(_PROTOBUF_PLUGIN_EXTRA_CACHE_ARGS -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=12.1 ) +set(_WALLET_CORE_EXTRA_CACHE_ARGS + -DTW_UNITY_BUILD:BOOL=ON +) + include(../CommonTargets.cmake) From df65f153d7958f9ee5d6b22f97e3ac9c8afd37e7 Mon Sep 17 00:00:00 2001 From: itsafuu Date: Wed, 29 Jul 2026 17:49:40 -0400 Subject: [PATCH 12/62] feat(01-03): vendor vk-bootstrap v1.4.357 as git submodule --- .gitmodules | 3 +++ vk-bootstrap | 1 + 2 files changed, 4 insertions(+) create mode 160000 vk-bootstrap diff --git a/.gitmodules b/.gitmodules index 0f3fe548..334d0aa3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -117,3 +117,6 @@ [submodule "protobuf"] path = protobuf url = https://github.com/protocolbuffers/protobuf.git +[submodule "vk-bootstrap"] + path = vk-bootstrap + url = https://github.com/charles-lunarg/vk-bootstrap.git diff --git a/vk-bootstrap b/vk-bootstrap new file mode 160000 index 00000000..556b79b1 --- /dev/null +++ b/vk-bootstrap @@ -0,0 +1 @@ +Subproject commit 556b79b165386f6c1a18362d30f2a076fdaa2778 From f2546b6c92864c7db165e77d287f7e2d5fd51af2 Mon Sep 17 00:00:00 2001 From: itsafuu Date: Wed, 29 Jul 2026 17:53:39 -0400 Subject: [PATCH 13/62] feat(01-03): add vk-bootstrap ExternalProject_Add CMake build wiring --- build/CommonTargets.cmake | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/build/CommonTargets.cmake b/build/CommonTargets.cmake index b57f02d4..522ab237 100644 --- a/build/CommonTargets.cmake +++ b/build/CommonTargets.cmake @@ -387,6 +387,20 @@ if(NOT ANDROID) DEPENDS Vulkan-Headers ) + # vk-bootstrap + ExternalProject_Add( + vk-bootstrap + PREFIX vk-bootstrap + SOURCE_DIR "${THIRDPARTY_DIR}/vk-bootstrap" + CMAKE_CACHE_ARGS + -DCMAKE_INSTALL_PREFIX:PATH= + -DVulkanHeaders_DIR:PATH=/share/cmake/VulkanHeaders + -DVK_BOOTSTRAP_TEST:BOOL=OFF + -DVK_BOOTSTRAP_INSTALL:BOOL=ON + ${_CMAKE_COMMON_CACHE_ARGS} + DEPENDS Vulkan-Headers + ) + set(ENV{VULKAN_SDK} "${CMAKE_CURRENT_BINARY_DIR}/Vulkan-Loader") set(vulkanTarget Vulkan-Loader) endif() From ee07ede65400d3d811e73768e8b91e4f06c9b06c Mon Sep 17 00:00:00 2001 From: itsafuu Date: Wed, 29 Jul 2026 21:02:32 -0400 Subject: [PATCH 14/62] chore(01-03): bump Vulkan-Headers and Vulkan-Loader to v1.4.357 for vk-bootstrap compatibility --- Vulkan-Headers | 2 +- Vulkan-Loader | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Vulkan-Headers b/Vulkan-Headers index 9dff1f57..e3b1eec0 160000 --- a/Vulkan-Headers +++ b/Vulkan-Headers @@ -1 +1 @@ -Subproject commit 9dff1f571ce25b92639854b89b28539602b6b97b +Subproject commit e3b1eec08173d6b825cd3ac88c885a63b621504a diff --git a/Vulkan-Loader b/Vulkan-Loader index 2534c1e2..5f157b62 160000 --- a/Vulkan-Loader +++ b/Vulkan-Loader @@ -1 +1 @@ -Subproject commit 2534c1e2327990e55f51b8a1f8328085e8e3ff31 +Subproject commit 5f157b62e333c63260d05d81bf66faa216ab0fb8 From 91d61d904785f7bab282306e294d7cc92f3b5d3c Mon Sep 17 00:00:00 2001 From: itsafuu Date: Wed, 29 Jul 2026 21:07:47 -0400 Subject: [PATCH 15/62] fix(01-03): use explicit VulkanHeaders_DIR path for vk-bootstrap (not self-referencing ) --- build/CommonTargets.cmake | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build/CommonTargets.cmake b/build/CommonTargets.cmake index 522ab237..fe8205c9 100644 --- a/build/CommonTargets.cmake +++ b/build/CommonTargets.cmake @@ -394,9 +394,8 @@ if(NOT ANDROID) SOURCE_DIR "${THIRDPARTY_DIR}/vk-bootstrap" CMAKE_CACHE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= - -DVulkanHeaders_DIR:PATH=/share/cmake/VulkanHeaders + -DVulkanHeaders_DIR:PATH=${CMAKE_CURRENT_BINARY_DIR}/Vulkan-Loader/share/cmake/VulkanHeaders -DVK_BOOTSTRAP_TEST:BOOL=OFF - -DVK_BOOTSTRAP_INSTALL:BOOL=ON ${_CMAKE_COMMON_CACHE_ARGS} DEPENDS Vulkan-Headers ) From d1a47b387e4e5936e5e5fc9cfbf17cd2b7c1b1c4 Mon Sep 17 00:00:00 2001 From: itsafuu Date: Thu, 30 Jul 2026 19:27:13 -0400 Subject: [PATCH 16/62] feat(02-02): vendor shaderc v2024.3, SPIRV-Tools, SPIRV-Headers as pinned git submodules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - shaderc pinned at v2024.3 (ff84893) — GLSL->SPIR-V compilation, matches Vulkan-1.3-targeting release line consistent with this project's pinned Vulkan-Headers/Loader ~1.3.302 - SPIRV-Tools pinned at 01c8438e — the exact commit shaderc's own DEPS file references for its v2024.3 tag (NOT shaderc main's current DEPS, which has since moved to a665e21f) — vendored as a separate, directly-linkable dependency so spvtools::SpirvTools::Validate() is callable without reaching into shaderc's internal, non-exported build tree - SPIRV-Headers pinned at 2a9b6f95 — same shaderc-v2024.3-DEPS-file cross-check, required transitive dependency of the standalone SPIRV-Tools build - shaderc's own nested glslang/spirv-tools/spirv-headers/etc. third_party/ deps are gclient-style (DEPS file + ./utils/git-sync-deps script), not git submodules, and are gitignored inside shaderc's own repo — populated via git-sync-deps for shaderc's own internal build, never committed anywhere --- .gitmodules | 9 +++++++++ SPIRV-Headers | 1 + SPIRV-Tools | 1 + shaderc | 1 + 4 files changed, 12 insertions(+) create mode 160000 SPIRV-Headers create mode 160000 SPIRV-Tools create mode 160000 shaderc diff --git a/.gitmodules b/.gitmodules index 334d0aa3..3ca3d87c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -120,3 +120,12 @@ [submodule "vk-bootstrap"] path = vk-bootstrap url = https://github.com/charles-lunarg/vk-bootstrap.git +[submodule "shaderc"] + path = shaderc + url = https://github.com/google/shaderc.git +[submodule "SPIRV-Headers"] + path = SPIRV-Headers + url = https://github.com/KhronosGroup/SPIRV-Headers.git +[submodule "SPIRV-Tools"] + path = SPIRV-Tools + url = https://github.com/KhronosGroup/SPIRV-Tools.git diff --git a/SPIRV-Headers b/SPIRV-Headers new file mode 160000 index 00000000..2a9b6f95 --- /dev/null +++ b/SPIRV-Headers @@ -0,0 +1 @@ +Subproject commit 2a9b6f951c7d6b04b6c21fe1bf3f475b68b84801 diff --git a/SPIRV-Tools b/SPIRV-Tools new file mode 160000 index 00000000..01c8438e --- /dev/null +++ b/SPIRV-Tools @@ -0,0 +1 @@ +Subproject commit 01c8438ee4ac52c248119b7e03e0b021f853b51a diff --git a/shaderc b/shaderc new file mode 160000 index 00000000..ff84893d --- /dev/null +++ b/shaderc @@ -0,0 +1 @@ +Subproject commit ff84893dd52d28f0b1737d2635733d952013bd9c From 32682483f1135d240b87d488a21d2c99cc74ba52 Mon Sep 17 00:00:00 2001 From: itsafuu Date: Thu, 30 Jul 2026 19:30:24 -0400 Subject: [PATCH 17/62] feat(02-02): add shaderc/SPIRV-Tools/SPIRV-Headers ExternalProject_Add vendoring + IMPORTED targets Adds shaderc::shaderc and SPIRV-Tools::SPIRV-Tools CMake targets to CommonTargets.cmake, following the existing Vulkan-Headers/Vulkan-Loader/vk-bootstrap ExternalProject_Add convention, with the deviations a real local build+install spike confirmed are required: - SPIRV-Tools DOES install a CMake package config by default, but the exported target is the bare, non-namespaced SPIRV-Tools-static/-shared (the upstream SPIRV-Tools ALIAS is build-tree-only, never exported) -- resolved via find_package(SPIRV-Tools CONFIG) + an ALIAS to the project-controlled SPIRV-Tools::SPIRV-Tools name, with a hand-rolled IMPORTED fallback if the installed config is ever unavailable. - shaderc installs no CMake package config at all (confirmed via the same spike, matching github.com/google/shaderc/issues/1369 and github.com/microsoft/vcpkg/issues/23208) -- hand-written IMPORTED target against the confirmed-real installed libshaderc_combined.a. Verified via an actual local configure+build+install of all three ExternalProject_Add targets (MinGW GCC 13.2.0/Ninja, the toolchain available in this environment) plus a standalone consumer executable that links both shaderc::shaderc and SPIRV-Tools::SPIRV-Tools, compiles a trivial GLSL fragment shader to SPIR-V via shaderc, and validates the result via spvtools::SpirvTools::Validate() -- both targets configure, build, link, and the compile+ validate round-trip is functionally correct end-to-end. --- build/CommonTargets.cmake | 86 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/build/CommonTargets.cmake b/build/CommonTargets.cmake index fe8205c9..f5fac500 100644 --- a/build/CommonTargets.cmake +++ b/build/CommonTargets.cmake @@ -402,6 +402,92 @@ if(NOT ANDROID) set(ENV{VULKAN_SDK} "${CMAKE_CURRENT_BINARY_DIR}/Vulkan-Loader") set(vulkanTarget Vulkan-Loader) + + # SPIRV-Headers (required transitive dependency of the standalone SPIRV-Tools build below; + # separate from shaderc's own nested, non-exported third_party/spirv-headers copy) + ExternalProject_Add( + SPIRV-Headers + PREFIX SPIRV-Headers + SOURCE_DIR "${THIRDPARTY_DIR}/SPIRV-Headers" + CMAKE_CACHE_ARGS + -DCMAKE_INSTALL_PREFIX:PATH= + ${_CMAKE_COMMON_CACHE_ARGS} + ) + + # SPIRV-Tools — vendored as its own, separately-linkable dependency (not reached through + # shaderc's internal, non-exported build tree) so spvtools::SpirvTools::Validate() (the + # SHADER-02 spirv-val gate) is directly callable. Pinned to the exact commit shaderc's own + # v2024.3 DEPS file references, to avoid SPIR-V dialect skew between what shaderc emits and + # what this validator checks. + ExternalProject_Add( + SPIRV-Tools + PREFIX SPIRV-Tools + SOURCE_DIR "${THIRDPARTY_DIR}/SPIRV-Tools" + CMAKE_CACHE_ARGS + -DCMAKE_INSTALL_PREFIX:PATH= + -DSPIRV-Headers_SOURCE_DIR:PATH=${THIRDPARTY_DIR}/SPIRV-Headers + -DSPIRV_SKIP_TESTS:BOOL=ON + -DSPIRV_SKIP_EXECUTABLES:BOOL=ON + ${_CMAKE_COMMON_CACHE_ARGS} + DEPENDS SPIRV-Headers + ) + + # SPIRV-Tools DOES install a CMake package config by default (confirmed via a real local + # build+install spike, 2026-07-30) — but the exported targets are the bare, non-namespaced + # `SPIRV-Tools-static`/`SPIRV-Tools-shared` (the upstream `SPIRV-Tools` ALIAS target is + # build-tree-only and is never exported by install(EXPORT)). Prefer the installed config's + # real target when available; fall back to a hand-written IMPORTED target only if the + # installed config is ever unavailable (e.g. a future SPIRV-Tools version disables its + # install-config path). + if(NOT TARGET SPIRV-Tools::SPIRV-Tools) + find_package(SPIRV-Tools CONFIG QUIET PATHS "${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools" NO_DEFAULT_PATH) + if(TARGET SPIRV-Tools-static) + add_library(SPIRV-Tools::SPIRV-Tools ALIAS SPIRV-Tools-static) + elseif(TARGET SPIRV-Tools-shared) + add_library(SPIRV-Tools::SPIRV-Tools ALIAS SPIRV-Tools-shared) + else() + add_library(SPIRV-Tools::SPIRV-Tools STATIC IMPORTED GLOBAL) + set_target_properties(SPIRV-Tools::SPIRV-Tools PROPERTIES + IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools/lib/libSPIRV-Tools.a" + INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools/include" + ) + endif() + add_dependencies(SPIRV-Tools::SPIRV-Tools SPIRV-Tools) + endif() + + # shaderc — GLSL->SPIR-V compilation (SHADER-01). Builds its own nested, non-exported copy of + # glslang/SPIRV-Tools/SPIRV-Headers from third_party/ (populated via shaderc's own + # ./utils/git-sync-deps, not git submodules — see 02-02 vendoring commit), entirely + # independently of the separately-vendored SPIRV-Tools/SPIRV-Headers above; both copies are + # pinned to matching commits so the SPIR-V dialect stays consistent between what shaderc + # emits and what this project's own SPIRV-Tools::SPIRV-Tools validates. + ExternalProject_Add( + shaderc + PREFIX shaderc + SOURCE_DIR "${THIRDPARTY_DIR}/shaderc" + CMAKE_CACHE_ARGS + -DCMAKE_INSTALL_PREFIX:PATH= + -DSHADERC_SKIP_TESTS:BOOL=ON + -DSHADERC_SKIP_EXAMPLES:BOOL=ON + -DSHADERC_SKIP_COPYRIGHT_CHECK:BOOL=ON + -DSHADERC_ENABLE_HLSL:BOOL=OFF + -DSHADERC_ENABLE_WGSL_OUTPUT:BOOL=OFF + ${_CMAKE_COMMON_CACHE_ARGS} + ) + + # shaderc installs no CMake package config (confirmed via a real local build+install spike, + # 2026-07-30, and cross-checked against github.com/google/shaderc/issues/1369 and + # github.com/microsoft/vcpkg/issues/23208) — hand-written IMPORTED target required. + # libshaderc_combined statically bundles glslang+SPIRV-Tools, minimizing separate-linking + # bookkeeping for consumers. + if(NOT TARGET shaderc::shaderc) + add_library(shaderc::shaderc STATIC IMPORTED GLOBAL) + set_target_properties(shaderc::shaderc PROPERTIES + IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/shaderc/lib/libshaderc_combined.a" + INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/shaderc/include" + ) + add_dependencies(shaderc::shaderc shaderc) + endif() endif() if(NOT APPLE OR (APPLE AND CMAKE_OSX_SYSROOT MATCHES "iPhoneOS")) From 99340560f11dcdc797e2d26dce819d9b1bc6b4d6 Mon Sep 17 00:00:00 2001 From: itsafuu Date: Thu, 30 Jul 2026 21:18:55 -0400 Subject: [PATCH 18/62] fix(02): use portable library extensions for shaderc/SPIRV-Tools IMPORTED targets The hand-written IMPORTED targets hardcoded .a extensions with a "lib" prefix (libshaderc_combined.a, libSPIRV-Tools.a) -- GCC/MinGW static-lib naming. Under this project's real MSVC/VS2022 generator the actual files are shaderc_combined.lib / SPIRV-Tools.lib (no prefix, .lib suffix), so the hardcoded path silently failed to find the built libraries. Switched to CMAKE_STATIC_LIBRARY_PREFIX/SUFFIX, which resolve correctly per toolchain. Confirmed by an actual rebuild against the real Windows/Release tree: shaderc_combined.lib and SPIRV-Tools.lib are found and linked. Also disables SPIRV-Tools' shared-lib build (BUILD_SHARED_LIBS:BOOL=OFF) since only the static targets are consumed. --- build/CommonTargets.cmake | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/build/CommonTargets.cmake b/build/CommonTargets.cmake index f5fac500..a49e863a 100644 --- a/build/CommonTargets.cmake +++ b/build/CommonTargets.cmake @@ -428,6 +428,7 @@ if(NOT ANDROID) -DSPIRV-Headers_SOURCE_DIR:PATH=${THIRDPARTY_DIR}/SPIRV-Headers -DSPIRV_SKIP_TESTS:BOOL=ON -DSPIRV_SKIP_EXECUTABLES:BOOL=ON + -DBUILD_SHARED_LIBS:BOOL=OFF ${_CMAKE_COMMON_CACHE_ARGS} DEPENDS SPIRV-Headers ) @@ -448,7 +449,7 @@ if(NOT ANDROID) else() add_library(SPIRV-Tools::SPIRV-Tools STATIC IMPORTED GLOBAL) set_target_properties(SPIRV-Tools::SPIRV-Tools PROPERTIES - IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools/lib/libSPIRV-Tools.a" + IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools/lib/${CMAKE_STATIC_LIBRARY_PREFIX}SPIRV-Tools${CMAKE_STATIC_LIBRARY_SUFFIX}" INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools/include" ) endif() @@ -483,7 +484,7 @@ if(NOT ANDROID) if(NOT TARGET shaderc::shaderc) add_library(shaderc::shaderc STATIC IMPORTED GLOBAL) set_target_properties(shaderc::shaderc PROPERTIES - IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/shaderc/lib/libshaderc_combined.a" + IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/shaderc/lib/${CMAKE_STATIC_LIBRARY_PREFIX}shaderc_combined${CMAKE_STATIC_LIBRARY_SUFFIX}" INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/shaderc/include" ) add_dependencies(shaderc::shaderc shaderc) From e5efd45b57dfd5f7fe798d33cbb4e66d7eef39a1 Mon Sep 17 00:00:00 2001 From: itsafuu Date: Fri, 31 Jul 2026 22:18:37 -0400 Subject: [PATCH 19/62] feat(05-01): extract render libs from if(NOT ANDROID) guard, add platform-conditional Vulkan wiring - Move SPIRV-Headers, SPIRV-Tools, vk-bootstrap, shaderc ExternalProject_Add blocks and their IMPORTED targets outside if(NOT ANDROID) to unconditional scope - Keep Vulkan-Headers and Vulkan-Loader inside if(NOT ANDROID) (NDK provides on Android, MoltenVK on Apple) - Add _VK_BOOTSTRAP_VULKAN_HEADERS_DIR platform-conditional variable: desktop uses Vulkan-Loader prefix, Android/iOS build Vulkan-Headers from source - Replace hardcoded VulkanHeaders_DIR in vk-bootstrap with _VK_BOOTSTRAP_VULKAN_HEADERS_DIR - Verify SGShaderCompiler and SGProcessors link chains: no changes needed (all render targets already linked unconditionally) --- build/CommonTargets.cmake | 203 ++++++++++++++++++++++---------------- 1 file changed, 117 insertions(+), 86 deletions(-) diff --git a/build/CommonTargets.cmake b/build/CommonTargets.cmake index a49e863a..8714c49f 100644 --- a/build/CommonTargets.cmake +++ b/build/CommonTargets.cmake @@ -387,108 +387,139 @@ if(NOT ANDROID) DEPENDS Vulkan-Headers ) - # vk-bootstrap - ExternalProject_Add( - vk-bootstrap - PREFIX vk-bootstrap - SOURCE_DIR "${THIRDPARTY_DIR}/vk-bootstrap" - CMAKE_CACHE_ARGS - -DCMAKE_INSTALL_PREFIX:PATH= - -DVulkanHeaders_DIR:PATH=${CMAKE_CURRENT_BINARY_DIR}/Vulkan-Loader/share/cmake/VulkanHeaders - -DVK_BOOTSTRAP_TEST:BOOL=OFF - ${_CMAKE_COMMON_CACHE_ARGS} - DEPENDS Vulkan-Headers - ) - set(ENV{VULKAN_SDK} "${CMAKE_CURRENT_BINARY_DIR}/Vulkan-Loader") set(vulkanTarget Vulkan-Loader) +endif() + +# SPIRV-Headers (required transitive dependency of the standalone SPIRV-Tools build below; +# separate from shaderc's own nested, non-exported third_party/spirv-headers copy) +ExternalProject_Add( + SPIRV-Headers + PREFIX SPIRV-Headers + SOURCE_DIR "${THIRDPARTY_DIR}/SPIRV-Headers" + CMAKE_CACHE_ARGS + -DCMAKE_INSTALL_PREFIX:PATH= + ${_CMAKE_COMMON_CACHE_ARGS} +) + +# SPIRV-Tools — vendored as its own, separately-linkable dependency (not reached through +# shaderc's internal, non-exported build tree) so spvtools::SpirvTools::Validate() (the +# SHADER-02 spirv-val gate) is directly callable. Pinned to the exact commit shaderc's own +# v2024.3 DEPS file references, to avoid SPIR-V dialect skew between what shaderc emits and +# what this validator checks. +ExternalProject_Add( + SPIRV-Tools + PREFIX SPIRV-Tools + SOURCE_DIR "${THIRDPARTY_DIR}/SPIRV-Tools" + CMAKE_CACHE_ARGS + -DCMAKE_INSTALL_PREFIX:PATH= + -DSPIRV-Headers_SOURCE_DIR:PATH=${THIRDPARTY_DIR}/SPIRV-Headers + -DSPIRV_SKIP_TESTS:BOOL=ON + -DSPIRV_SKIP_EXECUTABLES:BOOL=ON + -DBUILD_SHARED_LIBS:BOOL=OFF + ${_CMAKE_COMMON_CACHE_ARGS} + DEPENDS SPIRV-Headers +) + +# SPIRV-Tools DOES install a CMake package config by default (confirmed via a real local +# build+install spike, 2026-07-30) — but the exported targets are the bare, non-namespaced +# `SPIRV-Tools-static`/`SPIRV-Tools-shared` (the upstream `SPIRV-Tools` ALIAS target is +# build-tree-only and is never exported by install(EXPORT)). Prefer the installed config's +# real target when available; fall back to a hand-written IMPORTED target only if the +# installed config is ever unavailable (e.g. a future SPIRV-Tools version disables its +# install-config path). +if(NOT TARGET SPIRV-Tools::SPIRV-Tools) + find_package(SPIRV-Tools CONFIG QUIET PATHS "${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools" NO_DEFAULT_PATH) + if(TARGET SPIRV-Tools-static) + add_library(SPIRV-Tools::SPIRV-Tools ALIAS SPIRV-Tools-static) + elseif(TARGET SPIRV-Tools-shared) + add_library(SPIRV-Tools::SPIRV-Tools ALIAS SPIRV-Tools-shared) + else() + add_library(SPIRV-Tools::SPIRV-Tools STATIC IMPORTED GLOBAL) + set_target_properties(SPIRV-Tools::SPIRV-Tools PROPERTIES + IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools/lib/${CMAKE_STATIC_LIBRARY_PREFIX}SPIRV-Tools${CMAKE_STATIC_LIBRARY_SUFFIX}" + INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools/include" + ) + endif() + add_dependencies(SPIRV-Tools::SPIRV-Tools SPIRV-Tools) +endif() - # SPIRV-Headers (required transitive dependency of the standalone SPIRV-Tools build below; - # separate from shaderc's own nested, non-exported third_party/spirv-headers copy) +# Platform-conditional Vulkan dependency wiring for vk-bootstrap. +# Desktop: Vulkan-Headers is built inside if(NOT ANDROID) and installs to Vulkan-Loader prefix. +# Android/iOS: Vulkan-Headers must be built from source since the NDK/MoltenVK only provide +# raw headers, not a CMake package config. +if(NOT ANDROID AND NOT IOS) + set(_VK_BOOTSTRAP_VULKAN_HEADERS_DIR "${CMAKE_CURRENT_BINARY_DIR}/Vulkan-Loader/share/cmake/VulkanHeaders") + set(_VK_BOOTSTRAP_DEPENDS Vulkan-Headers) +elseif(ANDROID) ExternalProject_Add( - SPIRV-Headers - PREFIX SPIRV-Headers - SOURCE_DIR "${THIRDPARTY_DIR}/SPIRV-Headers" + Vulkan-Headers + PREFIX Vulkan-Headers + SOURCE_DIR "${THIRDPARTY_DIR}/Vulkan-Headers" CMAKE_CACHE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= ${_CMAKE_COMMON_CACHE_ARGS} ) - - # SPIRV-Tools — vendored as its own, separately-linkable dependency (not reached through - # shaderc's internal, non-exported build tree) so spvtools::SpirvTools::Validate() (the - # SHADER-02 spirv-val gate) is directly callable. Pinned to the exact commit shaderc's own - # v2024.3 DEPS file references, to avoid SPIR-V dialect skew between what shaderc emits and - # what this validator checks. + set(_VK_BOOTSTRAP_VULKAN_HEADERS_DIR "${CMAKE_CURRENT_BINARY_DIR}/Vulkan-Headers/share/cmake/VulkanHeaders") + set(_VK_BOOTSTRAP_DEPENDS Vulkan-Headers) +elseif(IOS) ExternalProject_Add( - SPIRV-Tools - PREFIX SPIRV-Tools - SOURCE_DIR "${THIRDPARTY_DIR}/SPIRV-Tools" + Vulkan-Headers + PREFIX Vulkan-Headers + SOURCE_DIR "${THIRDPARTY_DIR}/Vulkan-Headers" CMAKE_CACHE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= - -DSPIRV-Headers_SOURCE_DIR:PATH=${THIRDPARTY_DIR}/SPIRV-Headers - -DSPIRV_SKIP_TESTS:BOOL=ON - -DSPIRV_SKIP_EXECUTABLES:BOOL=ON - -DBUILD_SHARED_LIBS:BOOL=OFF ${_CMAKE_COMMON_CACHE_ARGS} - DEPENDS SPIRV-Headers ) + set(_VK_BOOTSTRAP_VULKAN_HEADERS_DIR "${CMAKE_CURRENT_BINARY_DIR}/Vulkan-Headers/share/cmake/VulkanHeaders") + set(_VK_BOOTSTRAP_DEPENDS Vulkan-Headers) +endif() - # SPIRV-Tools DOES install a CMake package config by default (confirmed via a real local - # build+install spike, 2026-07-30) — but the exported targets are the bare, non-namespaced - # `SPIRV-Tools-static`/`SPIRV-Tools-shared` (the upstream `SPIRV-Tools` ALIAS target is - # build-tree-only and is never exported by install(EXPORT)). Prefer the installed config's - # real target when available; fall back to a hand-written IMPORTED target only if the - # installed config is ever unavailable (e.g. a future SPIRV-Tools version disables its - # install-config path). - if(NOT TARGET SPIRV-Tools::SPIRV-Tools) - find_package(SPIRV-Tools CONFIG QUIET PATHS "${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools" NO_DEFAULT_PATH) - if(TARGET SPIRV-Tools-static) - add_library(SPIRV-Tools::SPIRV-Tools ALIAS SPIRV-Tools-static) - elseif(TARGET SPIRV-Tools-shared) - add_library(SPIRV-Tools::SPIRV-Tools ALIAS SPIRV-Tools-shared) - else() - add_library(SPIRV-Tools::SPIRV-Tools STATIC IMPORTED GLOBAL) - set_target_properties(SPIRV-Tools::SPIRV-Tools PROPERTIES - IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools/lib/${CMAKE_STATIC_LIBRARY_PREFIX}SPIRV-Tools${CMAKE_STATIC_LIBRARY_SUFFIX}" - INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools/include" - ) - endif() - add_dependencies(SPIRV-Tools::SPIRV-Tools SPIRV-Tools) - endif() +# vk-bootstrap +ExternalProject_Add( + vk-bootstrap + PREFIX vk-bootstrap + SOURCE_DIR "${THIRDPARTY_DIR}/vk-bootstrap" + CMAKE_CACHE_ARGS + -DCMAKE_INSTALL_PREFIX:PATH= + -DVulkanHeaders_DIR:PATH=${_VK_BOOTSTRAP_VULKAN_HEADERS_DIR} + -DVK_BOOTSTRAP_TEST:BOOL=OFF + ${_CMAKE_COMMON_CACHE_ARGS} + DEPENDS ${_VK_BOOTSTRAP_DEPENDS} +) + +# shaderc — GLSL->SPIR-V compilation (SHADER-01). Builds its own nested, non-exported copy of +# glslang/SPIRV-Tools/SPIRV-Headers from third_party/ (populated via shaderc's own +# ./utils/git-sync-deps, not git submodules — see 02-02 vendoring commit), entirely +# independently of the separately-vendored SPIRV-Tools/SPIRV-Headers above; both copies are +# pinned to matching commits so the SPIR-V dialect stays consistent between what shaderc +# emits and what this project's own SPIRV-Tools::SPIRV-Tools validates. +ExternalProject_Add( + shaderc + PREFIX shaderc + SOURCE_DIR "${THIRDPARTY_DIR}/shaderc" + CMAKE_CACHE_ARGS + -DCMAKE_INSTALL_PREFIX:PATH= + -DSHADERC_SKIP_TESTS:BOOL=ON + -DSHADERC_SKIP_EXAMPLES:BOOL=ON + -DSHADERC_SKIP_COPYRIGHT_CHECK:BOOL=ON + -DSHADERC_ENABLE_HLSL:BOOL=OFF + -DSHADERC_ENABLE_WGSL_OUTPUT:BOOL=OFF + ${_CMAKE_COMMON_CACHE_ARGS} +) - # shaderc — GLSL->SPIR-V compilation (SHADER-01). Builds its own nested, non-exported copy of - # glslang/SPIRV-Tools/SPIRV-Headers from third_party/ (populated via shaderc's own - # ./utils/git-sync-deps, not git submodules — see 02-02 vendoring commit), entirely - # independently of the separately-vendored SPIRV-Tools/SPIRV-Headers above; both copies are - # pinned to matching commits so the SPIR-V dialect stays consistent between what shaderc - # emits and what this project's own SPIRV-Tools::SPIRV-Tools validates. - ExternalProject_Add( - shaderc - PREFIX shaderc - SOURCE_DIR "${THIRDPARTY_DIR}/shaderc" - CMAKE_CACHE_ARGS - -DCMAKE_INSTALL_PREFIX:PATH= - -DSHADERC_SKIP_TESTS:BOOL=ON - -DSHADERC_SKIP_EXAMPLES:BOOL=ON - -DSHADERC_SKIP_COPYRIGHT_CHECK:BOOL=ON - -DSHADERC_ENABLE_HLSL:BOOL=OFF - -DSHADERC_ENABLE_WGSL_OUTPUT:BOOL=OFF - ${_CMAKE_COMMON_CACHE_ARGS} +# shaderc installs no CMake package config (confirmed via a real local build+install spike, +# 2026-07-30, and cross-checked against github.com/google/shaderc/issues/1369 and +# github.com/microsoft/vcpkg/issues/23208) — hand-written IMPORTED target required. +# libshaderc_combined statically bundles glslang+SPIRV-Tools, minimizing separate-linking +# bookkeeping for consumers. +if(NOT TARGET shaderc::shaderc) + add_library(shaderc::shaderc STATIC IMPORTED GLOBAL) + set_target_properties(shaderc::shaderc PROPERTIES + IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/shaderc/lib/${CMAKE_STATIC_LIBRARY_PREFIX}shaderc_combined${CMAKE_STATIC_LIBRARY_SUFFIX}" + INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/shaderc/include" ) - - # shaderc installs no CMake package config (confirmed via a real local build+install spike, - # 2026-07-30, and cross-checked against github.com/google/shaderc/issues/1369 and - # github.com/microsoft/vcpkg/issues/23208) — hand-written IMPORTED target required. - # libshaderc_combined statically bundles glslang+SPIRV-Tools, minimizing separate-linking - # bookkeeping for consumers. - if(NOT TARGET shaderc::shaderc) - add_library(shaderc::shaderc STATIC IMPORTED GLOBAL) - set_target_properties(shaderc::shaderc PROPERTIES - IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/shaderc/lib/${CMAKE_STATIC_LIBRARY_PREFIX}shaderc_combined${CMAKE_STATIC_LIBRARY_SUFFIX}" - INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/shaderc/include" - ) - add_dependencies(shaderc::shaderc shaderc) - endif() + add_dependencies(shaderc::shaderc shaderc) endif() if(NOT APPLE OR (APPLE AND CMAKE_OSX_SYSROOT MATCHES "iPhoneOS")) From 77695d11bd9ce8f098f35da71beb59aed1857d01 Mon Sep 17 00:00:00 2001 From: itsafuu Date: Fri, 31 Jul 2026 22:20:17 -0400 Subject: [PATCH 20/62] docs(05-02): add mobile thirdparty build guide for Android NDK and iOS Xcode - Document prerequisites: NDK r26+, Xcode 15+, CMake 3.22+, Python 3.7+ - Android build commands for arm64-v8a and armeabi-v7a ABIs - iOS build commands for arm64 device (PLATFORM=OS64, DEPLOYMENT_TARGET=15) - Expected static library outputs per platform - Link verification procedure via SuperGenius platform CMake configure - Troubleshooting: Python, ANDROID_STL, VulkanHeaders_DIR, memory, Xcode --- build/mobile/README.md | 207 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 build/mobile/README.md diff --git a/build/mobile/README.md b/build/mobile/README.md new file mode 100644 index 00000000..89cd88ca --- /dev/null +++ b/build/mobile/README.md @@ -0,0 +1,207 @@ +# Mobile Thirdparty Library Build Guide + +Build the render-specific thirdparty libraries (vk-bootstrap, SPIRV-Tools, shaderc, and Vulkan headers) +for Android (arm64-v8a, armeabi-v7a) and iOS (arm64 device). + +## Prerequisites + +### Both Platforms +- **Git** — submodules must be initialized: + ```bash + git submodule update --init --recursive + ``` +- **CMake** ≥ 3.22 +- **Python** 3.7+ (required by shaderc's bundled glslang for code generation) +- **Ninja** (optional but recommended for faster builds) + +### Android +- **Android NDK** r26 or later + - Set `ANDROID_NDK_HOME` environment variable, or pass `-DCMAKE_ANDROID_NDK=/path/to/ndk` to CMake + +### iOS +- **Xcode** 15+ with command-line tools +- **macOS** build host (iOS cross-compilation requires Apple toolchain) + +--- + +## Android Build Commands + +### arm64-v8a + +```bash +mkdir -p thirdparty/build/Android/Debug +cd thirdparty/build/Android/Debug +cmake .. -G "Ninja" \ + -DCMAKE_BUILD_TYPE=Debug \ + -DCMAKE_ANDROID_NDK=/path/to/ndk \ + -DANDROID_ABI=arm64-v8a +cmake --build . --parallel 8 +``` + +### armeabi-v7a + +```bash +mkdir -p thirdparty/build/Android/Debug +cd thirdparty/build/Android/Debug +cmake .. -G "Ninja" \ + -DCMAKE_BUILD_TYPE=Debug \ + -DCMAKE_ANDROID_NDK=/path/to/ndk \ + -DANDROID_ABI=armeabi-v7a +cmake --build . --parallel 8 +``` + +Replace `/path/to/ndk` with your actual NDK path (e.g. `$ANDROID_NDK_HOME` or +`~/Android/Sdk/ndk/26.3.11579264`). Adjust `--parallel` based on available CPU cores. + +The NDK toolchain propagates `ANDROID_STL=c++_static`, `ANDROID_NATIVE_API_LEVEL=28`, and +`CMAKE_FIND_ROOT_PATH` automatically via `_CMAKE_COMMON_CACHE_ARGS` set in +`thirdparty/build/Android/CMakeLists.txt`. + +--- + +## iOS Build Commands + +### arm64 Device + +```bash +mkdir -p thirdparty/build/iOS/Debug +cd thirdparty/build/iOS/Debug +cmake .. -G "Xcode" \ + -DCMAKE_BUILD_TYPE=Debug \ + -DCMAKE_TOOLCHAIN_FILE=../apple.toolchain.cmake \ + -DPLATFORM=OS64 \ + -DDEPLOYMENT_TARGET=15 +cmake --build . --config Debug --parallel 8 +``` + +To use Ninja instead of Xcode generator: +```bash +cmake .. -G "Ninja" \ + -DCMAKE_BUILD_TYPE=Debug \ + -DCMAKE_TOOLCHAIN_FILE=../apple.toolchain.cmake \ + -DPLATFORM=OS64 \ + -DDEPLOYMENT_TARGET=15 +cmake --build . --parallel 8 +``` + +The apple toolchain propagates `PLATFORM`, `DEPLOYMENT_TARGET`, and +`NAMED_LANGUAGE_SUPPORT`/`ENABLE_BITCODE`/`ENABLE_ARC`/`ENABLE_VISIBILITY` +automatically via `_CMAKE_COMMON_CACHE_ARGS` set in `thirdparty/build/iOS/CMakeLists.txt`. + +Note: iOS builds must run on a macOS host with Xcode installed. Simulator architectures +are not supported — arm64 device only. + +--- + +## Expected Build Outputs + +After a successful build, the following static libraries are produced: + +| Library | Android Path | iOS Path | +|---------|-------------|----------| +| vk-bootstrap | `thirdparty/build/Android/Debug/vk-bootstrap/lib/libvk-bootstrap.a` | `thirdparty/build/iOS/Debug/vk-bootstrap/lib/libvk-bootstrap.a` | +| SPIRV-Tools | `thirdparty/build/Android/Debug/SPIRV-Tools/lib/libSPIRV-Tools.a` | `thirdparty/build/iOS/Debug/SPIRV-Tools/lib/libSPIRV-Tools.a` | +| shaderc | `thirdparty/build/Android/Debug/shaderc/lib/libshaderc_combined.a` | `thirdparty/build/iOS/Debug/shaderc/lib/libshaderc_combined.a` | +| Vulkan Headers | `thirdparty/build/Android/Debug/Vulkan-Headers/share/cmake/VulkanHeaders/` | `thirdparty/build/iOS/Debug/Vulkan-Headers/share/cmake/VulkanHeaders/` | + +Additional platform-specific outputs: + +- **Android:** Vulkan loader is provided by the NDK as `libvulkan.so` — loaded at runtime + on the device. No separate build step required. +- **iOS:** MoltenVK (Vulkan-over-Metal) is built separately by + `thirdparty/build/iOS/CMakeLists.txt` and produces + `thirdparty/build/iOS/Debug/moltenvk/build/lib/MoltenVK.xcframework`. + +--- + +## Link Verification + +After building the thirdparty libraries, verify the SGProcessingManager render path +resolves correctly for the target platform: + +### Android + +```bash +cd SuperGenius/build/Android +cmake .. \ + -DCMAKE_ANDROID_NDK=/path/to/ndk \ + -DANDROID_ABI=arm64-v8a \ + -D_THIRDPARTY_BUILD_DIR=../../thirdparty/build/Android/Debug +``` + +### iOS + +```bash +cd SuperGenius/build/iOS +cmake .. \ + -DCMAKE_TOOLCHAIN_FILE=../apple.toolchain.cmake \ + -DPLATFORM=OS64 \ + -DDEPLOYMENT_TARGET=15 \ + -D_THIRDPARTY_BUILD_DIR=../../thirdparty/build/iOS/Debug +``` + +A successful CMake configure — with no `find_package` or `target_link_libraries` errors +for `shaderc::shaderc`, `SPIRV-Tools::SPIRV-Tools`, `Vulkan::Vulkan`, or +`vk-bootstrap::vk-bootstrap` — proves the link chain is intact. + +Build logs should be captured as evidence per the phase verification requirements. + +--- + +## Troubleshooting + +### shaderc build fails with "Python not found" + +**Cause:** shaderc's bundled glslang uses Python for code generation during the build. + +**Fix:** Ensure Python 3.7+ is on `PATH`: +```bash +python3 --version +# If missing, install Python 3.7+ and add to PATH +``` + +### SPIRV-Tools build fails on Android with C++ standard library errors + +**Cause:** `ANDROID_STL` not propagated correctly. + +**Fix:** Verify `ANDROID_STL=c++_static` is in `_CMAKE_COMMON_CACHE_ARGS` +(automatically set by `thirdparty/build/Android/CMakeLists.txt`). If building +standalone, pass it explicitly: +```bash +cmake .. -DANDROID_STL=c++_static ... +``` + +### vk-bootstrap configure fails with "VulkanHeaders not found" + +**Cause:** `_VK_BOOTSTRAP_VULKAN_HEADERS_DIR` resolution in +`thirdparty/build/CommonTargets.cmake` points to a path that doesn't exist. + +**Fix:** Check that Vulkan-Headers built successfully: +- Android: `ls thirdparty/build/Android/Debug/Vulkan-Headers/share/cmake/VulkanHeaders/` +- iOS: `ls thirdparty/build/iOS/Debug/Vulkan-Headers/share/cmake/VulkanHeaders/` +- Desktop: `ls thirdparty/build/{Platform}/Debug/Vulkan-Loader/share/cmake/VulkanHeaders/` + +### Build runs out of memory + +**Cause:** shaderc's bundled glslang build is memory-intensive, especially with high +`--parallel` values. + +**Fix:** Reduce parallelism: +```bash +cmake --build . --parallel 2 +``` +Or build incrementally (build shaderc first, then the rest): +```bash +cmake --build . --target shaderc --parallel 2 +cmake --build . --parallel 8 +``` + +### iOS build fails with "unknown platform" + +**Cause:** The apple toolchain file or Xcode command-line tools not found. + +**Fix:** Ensure Xcode and command-line tools are installed: +```bash +xcode-select --install +xcodebuild -version +``` From 50485f8f21c3a4ed6ea9e1a379b1bf14c4053604 Mon Sep 17 00:00:00 2001 From: itsafuu Date: Mon, 3 Aug 2026 16:24:19 -0400 Subject: [PATCH 21/62] Android build fixes --- build/CommonTargets.cmake | 73 ++++++++------------------------------- 1 file changed, 14 insertions(+), 59 deletions(-) diff --git a/build/CommonTargets.cmake b/build/CommonTargets.cmake index 8714c49f..1b6a75f6 100644 --- a/build/CommonTargets.cmake +++ b/build/CommonTargets.cmake @@ -391,58 +391,11 @@ if(NOT ANDROID) set(vulkanTarget Vulkan-Loader) endif() -# SPIRV-Headers (required transitive dependency of the standalone SPIRV-Tools build below; -# separate from shaderc's own nested, non-exported third_party/spirv-headers copy) -ExternalProject_Add( - SPIRV-Headers - PREFIX SPIRV-Headers - SOURCE_DIR "${THIRDPARTY_DIR}/SPIRV-Headers" - CMAKE_CACHE_ARGS - -DCMAKE_INSTALL_PREFIX:PATH= - ${_CMAKE_COMMON_CACHE_ARGS} -) - -# SPIRV-Tools — vendored as its own, separately-linkable dependency (not reached through -# shaderc's internal, non-exported build tree) so spvtools::SpirvTools::Validate() (the -# SHADER-02 spirv-val gate) is directly callable. Pinned to the exact commit shaderc's own -# v2024.3 DEPS file references, to avoid SPIR-V dialect skew between what shaderc emits and -# what this validator checks. -ExternalProject_Add( - SPIRV-Tools - PREFIX SPIRV-Tools - SOURCE_DIR "${THIRDPARTY_DIR}/SPIRV-Tools" - CMAKE_CACHE_ARGS - -DCMAKE_INSTALL_PREFIX:PATH= - -DSPIRV-Headers_SOURCE_DIR:PATH=${THIRDPARTY_DIR}/SPIRV-Headers - -DSPIRV_SKIP_TESTS:BOOL=ON - -DSPIRV_SKIP_EXECUTABLES:BOOL=ON - -DBUILD_SHARED_LIBS:BOOL=OFF - ${_CMAKE_COMMON_CACHE_ARGS} - DEPENDS SPIRV-Headers -) - -# SPIRV-Tools DOES install a CMake package config by default (confirmed via a real local -# build+install spike, 2026-07-30) — but the exported targets are the bare, non-namespaced -# `SPIRV-Tools-static`/`SPIRV-Tools-shared` (the upstream `SPIRV-Tools` ALIAS target is -# build-tree-only and is never exported by install(EXPORT)). Prefer the installed config's -# real target when available; fall back to a hand-written IMPORTED target only if the -# installed config is ever unavailable (e.g. a future SPIRV-Tools version disables its -# install-config path). -if(NOT TARGET SPIRV-Tools::SPIRV-Tools) - find_package(SPIRV-Tools CONFIG QUIET PATHS "${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools" NO_DEFAULT_PATH) - if(TARGET SPIRV-Tools-static) - add_library(SPIRV-Tools::SPIRV-Tools ALIAS SPIRV-Tools-static) - elseif(TARGET SPIRV-Tools-shared) - add_library(SPIRV-Tools::SPIRV-Tools ALIAS SPIRV-Tools-shared) - else() - add_library(SPIRV-Tools::SPIRV-Tools STATIC IMPORTED GLOBAL) - set_target_properties(SPIRV-Tools::SPIRV-Tools PROPERTIES - IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools/lib/${CMAKE_STATIC_LIBRARY_PREFIX}SPIRV-Tools${CMAKE_STATIC_LIBRARY_SUFFIX}" - INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools/include" - ) - endif() - add_dependencies(SPIRV-Tools::SPIRV-Tools SPIRV-Tools) -endif() +# SPIRV-Tools and SPIRV-Headers are no longer built as standalone ExternalProjects. +# libshaderc_combined (built by shaderc below) statically bundles the exact same SPIRV-Tools +# code at the exact same pinned commit (v2024.3 DEPS), so linking shaderc::shaderc already +# provides all SPIRV-Tools symbols. The spirv-tools include path is added to +# shaderc::shaderc's INTERFACE_INCLUDE_DIRECTORIES below. # Platform-conditional Vulkan dependency wiring for vk-bootstrap. # Desktop: Vulkan-Headers is built inside if(NOT ANDROID) and installs to Vulkan-Loader prefix. @@ -490,14 +443,15 @@ ExternalProject_Add( # shaderc — GLSL->SPIR-V compilation (SHADER-01). Builds its own nested, non-exported copy of # glslang/SPIRV-Tools/SPIRV-Headers from third_party/ (populated via shaderc's own -# ./utils/git-sync-deps, not git submodules — see 02-02 vendoring commit), entirely -# independently of the separately-vendored SPIRV-Tools/SPIRV-Headers above; both copies are -# pinned to matching commits so the SPIR-V dialect stays consistent between what shaderc -# emits and what this project's own SPIRV-Tools::SPIRV-Tools validates. +# ./utils/git-sync-deps which reads DEPS for pinned commits). libshaderc_combined +# statically bundles all of these, so consumers linking shaderc::shaderc automatically +# get SPIRV-Tools symbols for the SHADER-02 spirv-val gate. ExternalProject_Add( shaderc PREFIX shaderc SOURCE_DIR "${THIRDPARTY_DIR}/shaderc" + PATCH_COMMAND + python3 "${THIRDPARTY_DIR}/shaderc/utils/git-sync-deps" CMAKE_CACHE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= -DSHADERC_SKIP_TESTS:BOOL=ON @@ -511,13 +465,14 @@ ExternalProject_Add( # shaderc installs no CMake package config (confirmed via a real local build+install spike, # 2026-07-30, and cross-checked against github.com/google/shaderc/issues/1369 and # github.com/microsoft/vcpkg/issues/23208) — hand-written IMPORTED target required. -# libshaderc_combined statically bundles glslang+SPIRV-Tools, minimizing separate-linking -# bookkeeping for consumers. +# libshaderc_combined statically bundles glslang+SPIRV-Tools, so consumers that link +# shaderc::shaderc automatically get SPIRV-Tools symbols (SHADER-02 spirv-val gate). +# The spirv-tools include path is added here so resolves. if(NOT TARGET shaderc::shaderc) add_library(shaderc::shaderc STATIC IMPORTED GLOBAL) set_target_properties(shaderc::shaderc PROPERTIES IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/shaderc/lib/${CMAKE_STATIC_LIBRARY_PREFIX}shaderc_combined${CMAKE_STATIC_LIBRARY_SUFFIX}" - INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/shaderc/include" + INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/shaderc/include;${THIRDPARTY_DIR}/shaderc/third_party/spirv-tools/include" ) add_dependencies(shaderc::shaderc shaderc) endif() From 0d4efe063fdb3b28b14b0f05179b802e2cc34952 Mon Sep 17 00:00:00 2001 From: itsafuu Date: Mon, 3 Aug 2026 16:36:30 -0400 Subject: [PATCH 22/62] Clean up pointless platform detection and duplication of the same cmake code --- build/CommonTargets.cmake | 61 ++++++++++----------------------------- 1 file changed, 15 insertions(+), 46 deletions(-) diff --git a/build/CommonTargets.cmake b/build/CommonTargets.cmake index 1b6a75f6..b4290ac0 100644 --- a/build/CommonTargets.cmake +++ b/build/CommonTargets.cmake @@ -359,25 +359,25 @@ set(_FINDPACKAGE_libp2p_CONFIG_DIR "${CMAKE_CURRENT_BINARY_DIR}/libp2p/lib/cmake set(_FINDPACKAGE_libp2p_LIBRARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/libp2p/lib") set(_FINDPACKAGE_LIBP2P_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/libp2p/include") -if(NOT ANDROID) - # Vulkan-Headers - ExternalProject_Add( - Vulkan-Headers - PREFIX Vulkan-Headers - SOURCE_DIR "${THIRDPARTY_DIR}/Vulkan-Headers" - CMAKE_CACHE_ARGS - -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/Vulkan-Loader - ${_CMAKE_COMMON_CACHE_ARGS} - ) +# Vulkan-Headers — single build for all platforms. +ExternalProject_Add( + Vulkan-Headers + PREFIX Vulkan-Headers + SOURCE_DIR "${THIRDPARTY_DIR}/Vulkan-Headers" + CMAKE_CACHE_ARGS + -DCMAKE_INSTALL_PREFIX:PATH= + ${_CMAKE_COMMON_CACHE_ARGS} +) - # Vulkan-Loader +# Vulkan-Loader — desktop only (Android/iOS use platform-native loaders). +if(NOT ANDROID) ExternalProject_Add( Vulkan-Loader PREFIX Vulkan-Loader SOURCE_DIR "${THIRDPARTY_DIR}/Vulkan-Loader" CMAKE_CACHE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= - -DVulkanHeaders_DIR:PATH=/share/cmake/VulkanHeaders + -DVulkanHeaders_DIR:PATH=${CMAKE_CURRENT_BINARY_DIR}/Vulkan-Headers/share/cmake/VulkanHeaders -DBUILD_WSI_XCB_SUPPORT:BOOL=OFF -DBUILD_WSI_XLIB_SUPPORT:BOOL=OFF -DBUILD_WSI_WAYLAND_SUPPORT:BOOL=OFF @@ -397,48 +397,17 @@ endif() # provides all SPIRV-Tools symbols. The spirv-tools include path is added to # shaderc::shaderc's INTERFACE_INCLUDE_DIRECTORIES below. -# Platform-conditional Vulkan dependency wiring for vk-bootstrap. -# Desktop: Vulkan-Headers is built inside if(NOT ANDROID) and installs to Vulkan-Loader prefix. -# Android/iOS: Vulkan-Headers must be built from source since the NDK/MoltenVK only provide -# raw headers, not a CMake package config. -if(NOT ANDROID AND NOT IOS) - set(_VK_BOOTSTRAP_VULKAN_HEADERS_DIR "${CMAKE_CURRENT_BINARY_DIR}/Vulkan-Loader/share/cmake/VulkanHeaders") - set(_VK_BOOTSTRAP_DEPENDS Vulkan-Headers) -elseif(ANDROID) - ExternalProject_Add( - Vulkan-Headers - PREFIX Vulkan-Headers - SOURCE_DIR "${THIRDPARTY_DIR}/Vulkan-Headers" - CMAKE_CACHE_ARGS - -DCMAKE_INSTALL_PREFIX:PATH= - ${_CMAKE_COMMON_CACHE_ARGS} - ) - set(_VK_BOOTSTRAP_VULKAN_HEADERS_DIR "${CMAKE_CURRENT_BINARY_DIR}/Vulkan-Headers/share/cmake/VulkanHeaders") - set(_VK_BOOTSTRAP_DEPENDS Vulkan-Headers) -elseif(IOS) - ExternalProject_Add( - Vulkan-Headers - PREFIX Vulkan-Headers - SOURCE_DIR "${THIRDPARTY_DIR}/Vulkan-Headers" - CMAKE_CACHE_ARGS - -DCMAKE_INSTALL_PREFIX:PATH= - ${_CMAKE_COMMON_CACHE_ARGS} - ) - set(_VK_BOOTSTRAP_VULKAN_HEADERS_DIR "${CMAKE_CURRENT_BINARY_DIR}/Vulkan-Headers/share/cmake/VulkanHeaders") - set(_VK_BOOTSTRAP_DEPENDS Vulkan-Headers) -endif() - -# vk-bootstrap +# vk-bootstrap — depends on the single Vulkan-Headers build above. ExternalProject_Add( vk-bootstrap PREFIX vk-bootstrap SOURCE_DIR "${THIRDPARTY_DIR}/vk-bootstrap" CMAKE_CACHE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= - -DVulkanHeaders_DIR:PATH=${_VK_BOOTSTRAP_VULKAN_HEADERS_DIR} + -DVulkanHeaders_DIR:PATH=${CMAKE_CURRENT_BINARY_DIR}/Vulkan-Headers/share/cmake/VulkanHeaders -DVK_BOOTSTRAP_TEST:BOOL=OFF ${_CMAKE_COMMON_CACHE_ARGS} - DEPENDS ${_VK_BOOTSTRAP_DEPENDS} + DEPENDS Vulkan-Headers ) # shaderc — GLSL->SPIR-V compilation (SHADER-01). Builds its own nested, non-exported copy of From 3865c5b946edcb0c833ddc5381e91b4207cb4098 Mon Sep 17 00:00:00 2001 From: itsafuu Date: Mon, 3 Aug 2026 18:22:49 -0400 Subject: [PATCH 23/62] Remove spirv, shaderc takes care of these now --- .gitmodules | 6 ------ SPIRV-Headers | 1 - SPIRV-Tools | 1 - 3 files changed, 8 deletions(-) delete mode 160000 SPIRV-Headers delete mode 160000 SPIRV-Tools diff --git a/.gitmodules b/.gitmodules index 3ca3d87c..fbef40a8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -123,9 +123,3 @@ [submodule "shaderc"] path = shaderc url = https://github.com/google/shaderc.git -[submodule "SPIRV-Headers"] - path = SPIRV-Headers - url = https://github.com/KhronosGroup/SPIRV-Headers.git -[submodule "SPIRV-Tools"] - path = SPIRV-Tools - url = https://github.com/KhronosGroup/SPIRV-Tools.git diff --git a/SPIRV-Headers b/SPIRV-Headers deleted file mode 160000 index 2a9b6f95..00000000 --- a/SPIRV-Headers +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2a9b6f951c7d6b04b6c21fe1bf3f475b68b84801 diff --git a/SPIRV-Tools b/SPIRV-Tools deleted file mode 160000 index 01c8438e..00000000 --- a/SPIRV-Tools +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 01c8438ee4ac52c248119b7e03e0b021f853b51a From f3ea49c4b3c6e3731c27ba10ee341005b914588c Mon Sep 17 00:00:00 2001 From: itsafuu Date: Fri, 7 Aug 2026 00:24:32 -0400 Subject: [PATCH 24/62] Find python3 instead of python3 invoke directly --- build/CommonTargets.cmake | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/build/CommonTargets.cmake b/build/CommonTargets.cmake index b4290ac0..aee70b4f 100644 --- a/build/CommonTargets.cmake +++ b/build/CommonTargets.cmake @@ -1,3 +1,6 @@ +# Python3 — required by shaderc patch step (git-sync-deps) +find_package(Python3 COMPONENTS Interpreter REQUIRED) + # GTest ExternalProject_Add(GTest PREFIX GTest @@ -420,7 +423,7 @@ ExternalProject_Add( PREFIX shaderc SOURCE_DIR "${THIRDPARTY_DIR}/shaderc" PATCH_COMMAND - python3 "${THIRDPARTY_DIR}/shaderc/utils/git-sync-deps" + ${Python3_EXECUTABLE} "${THIRDPARTY_DIR}/shaderc/utils/git-sync-deps" CMAKE_CACHE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= -DSHADERC_SKIP_TESTS:BOOL=ON From bf2b3d7c876b8f6a705a4e8a8c9d94b1d95d139f Mon Sep 17 00:00:00 2001 From: itsafuu Date: Thu, 20 Aug 2026 22:20:06 -0400 Subject: [PATCH 25/62] chore: bump MNN to pick up FP4DequantUtils.hpp header registration --- MNN | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MNN b/MNN index 84b4cac8..73a27ee6 160000 --- a/MNN +++ b/MNN @@ -1 +1 @@ -Subproject commit 84b4cac8d60633ae5ed94149732ddf814bbb2e2f +Subproject commit 73a27ee659d403b8361c866b816f528537cfa2e8 From ec4fde52715298f1d3e20f652b12c7b80f971d29 Mon Sep 17 00:00:00 2001 From: Eduardo Menges Mattje Date: Fri, 21 Aug 2026 10:10:26 -0300 Subject: [PATCH 26/62] Optimized soralog --- soralog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soralog b/soralog index cab69fd8..a77e0bf2 160000 --- a/soralog +++ b/soralog @@ -1 +1 @@ -Subproject commit cab69fd83d9c0f85a11f47673c3dec9494aa6d01 +Subproject commit a77e0bf2a7bc1b7e25fc21e955965f0f021baa61 From f181702dca864d3242a5f1f8a1ce9be8f381f33a Mon Sep 17 00:00:00 2001 From: Henrique A Klein Date: Fri, 21 Aug 2026 14:25:00 -0300 Subject: [PATCH 27/62] chore: update ipfs-pubsub publish result dependency --- ipfs-pubsub | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipfs-pubsub b/ipfs-pubsub index 16056368..4f5ece68 160000 --- a/ipfs-pubsub +++ b/ipfs-pubsub @@ -1 +1 @@ -Subproject commit 16056368f1d6ee33aa1d389cbf2c35dd143a6beb +Subproject commit 4f5ece686f91f1ea648ce20e91edc1223c649cb6 From 636de21c51186923071b6c3e10f4ec102ea9bb1c Mon Sep 17 00:00:00 2001 From: Henrique A Klein Date: Fri, 21 Aug 2026 15:56:06 -0300 Subject: [PATCH 28/62] chore: update ipfs-pubsub publish result dependency --- ipfs-pubsub | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipfs-pubsub b/ipfs-pubsub index 4f5ece68..6f337ce3 160000 --- a/ipfs-pubsub +++ b/ipfs-pubsub @@ -1 +1 @@ -Subproject commit 4f5ece686f91f1ea648ce20e91edc1223c649cb6 +Subproject commit 6f337ce3ac48911ab9847a85f5743015d61cc18f From 2132a8b90d7c9977adca40912d7caf5b6aaa1881 Mon Sep 17 00:00:00 2001 From: Eduardo Menges Mattje Date: Thu, 27 Aug 2026 13:50:25 -0300 Subject: [PATCH 29/62] Fixed dependency cycle in `ipfs-lite-cpp` --- ipfs-lite-cpp | 2 +- ipfs-pubsub | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ipfs-lite-cpp b/ipfs-lite-cpp index fef678c8..4011803c 160000 --- a/ipfs-lite-cpp +++ b/ipfs-lite-cpp @@ -1 +1 @@ -Subproject commit fef678c8d151900170304d7e6bee740924d74d32 +Subproject commit 4011803cec2381dad5c745a845e871bf1a74b4aa diff --git a/ipfs-pubsub b/ipfs-pubsub index 6f337ce3..16056368 160000 --- a/ipfs-pubsub +++ b/ipfs-pubsub @@ -1 +1 @@ -Subproject commit 6f337ce3ac48911ab9847a85f5743015d61cc18f +Subproject commit 16056368f1d6ee33aa1d389cbf2c35dd143a6beb From be14504d5b91447a82aebece8a34f09ce06f2c5c Mon Sep 17 00:00:00 2001 From: Eduardo Menges Mattje Date: Fri, 28 Aug 2026 17:11:04 -0300 Subject: [PATCH 30/62] Compile wallet-core against the top-level json submodule Pass WALLET_CORE_JSON_INCLUDE_DIR=${THIRDPARTY_DIR}/json/include (v3.12.0) to the wallet-core external project so it stops compiling against its own pinned json copy (v3.11.2-51), which predates upstream's fix for the deprecated std::char_traits instantiations (issue #114). Co-Authored-By: Claude --- build/CommonTargets.cmake | 3 +++ wallet-core | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/build/CommonTargets.cmake b/build/CommonTargets.cmake index b57f02d4..9374aa11 100644 --- a/build/CommonTargets.cmake +++ b/build/CommonTargets.cmake @@ -614,6 +614,9 @@ ExternalProject_Add(wallet-core SOURCE_DIR "${THIRDPARTY_DIR}/wallet-core" CMAKE_CACHE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= + # Use the in-tree json submodule checkout (v3.12.0) instead of wallet-core's own + # pinned copy, which predates the std::char_traits fix (issue #114). + -DWALLET_CORE_JSON_INCLUDE_DIR:PATH=${THIRDPARTY_DIR}/json/include -Dabsl_DIR:PATH=${absl_DIR} -DProtobuf_DIR:PATH=${Protobuf_DIR} -Dprotobuf_MODULE_COMPATIBLE:BOOL=ON diff --git a/wallet-core b/wallet-core index a1554a1e..02bd398e 160000 --- a/wallet-core +++ b/wallet-core @@ -1 +1 @@ -Subproject commit a1554a1e8a14587d151156edf0c0c88d6f2de27d +Subproject commit 02bd398e213527cd43bd01a584029a3453575c13 From 8f78cb8e85f7fb09fd1a0024448d503f244eec23 Mon Sep 17 00:00:00 2001 From: Eduardo Menges Mattje Date: Fri, 28 Aug 2026 17:13:53 -0300 Subject: [PATCH 31/62] Removed rendundancy in actions --- .github/workflows/build-targets.yml | 767 +++++---------------- .github/workflows/build.yml | 334 +++++++-- .github/workflows/setup-windows-runner.yml | 69 -- .github/workflows/test-build.yml | 60 -- AGENTS.md | 5 +- README.md | 26 +- 6 files changed, 462 insertions(+), 799 deletions(-) delete mode 100644 .github/workflows/setup-windows-runner.yml delete mode 100644 .github/workflows/test-build.yml diff --git a/.github/workflows/build-targets.yml b/.github/workflows/build-targets.yml index bcbad0fc..a99e3dd0 100644 --- a/.github/workflows/build-targets.yml +++ b/.github/workflows/build-targets.yml @@ -1,597 +1,170 @@ -name: Multiplatform build and upload - -on: - workflow_dispatch: - inputs: - tag: - description: "Release tag" - required: false - type: string - build_android_arm64v8a_release: - description: 'Build Android arm64-v8a Release' - required: true - default: true - type: boolean - build_android_arm64v8a_debug: - description: 'Build Android arm64-v8a Debug' - required: true - default: true - type: boolean - build_android_armv7a_release: - description: 'Build Android armeabi-v7a Release' - required: true - default: true - type: boolean - build_android_armv7a_debug: - description: 'Build Android armeabi-v7a Debug' - required: true - default: true - type: boolean - build_ios_release: - description: 'Build iOS Release' - required: true - default: true - type: boolean - build_ios_debug: - description: 'Build iOS Debug' - required: true - default: true - type: boolean - build_osx_release: - description: 'Build OSX Release' - required: true - default: true - type: boolean - build_osx_debug: - description: 'Build OSX Debug' - required: true - default: true - type: boolean - build_linux_x86_64_release: - description: 'Build Linux x86_64 Release' - required: true - default: true - type: boolean - build_linux_x86_64_debug: - description: 'Build Linux x86_64 Debug' - required: true - default: true - type: boolean - build_linux_aarch64_release: - description: 'Build Linux aarch64 Release' - required: true - default: true - type: boolean - build_linux_aarch64_debug: - description: 'Build Linux aarch64 Debug' - required: true - default: true - type: boolean - build_windows_release: - description: 'Build Windows Release' - required: true - default: true - type: boolean - build_windows_debug: - description: 'Build Windows Debug' - required: true - default: true - type: boolean - sgns_enable_release_symbols: - description: 'Enable SGNS release symbols in CMake configure' - required: true - default: false - type: boolean - -env: - GH_TOKEN: ${{ secrets.GNUS_TOKEN_1 }} - SGNS_ENABLE_RELEASE_SYMBOLS: ${{ inputs.sgns_enable_release_symbols && 'ON' || 'OFF' }} -jobs: - resolve-runners: - runs-on: ubuntu-latest - outputs: - linux_x64: ${{ steps.pick.outputs.linux_x64 }} - linux_arm: ${{ steps.pick.outputs.linux_arm }} - windows: ${{ steps.pick.outputs.windows }} - mac: ${{ steps.pick.outputs.mac }} - steps: - - name: Check self-hosted runner availability - id: pick - env: - REPO: ${{ github.repository }} - run: | - set -euo pipefail - ORG="${REPO%%/*}" - repo_err="$(mktemp)" - org_err="$(mktemp)" - - # Some org-scoped runners may not show up via the repo endpoint for this token. - # Query both scopes and merge the results. - if repo_data="$(gh api "/repos/$REPO/actions/runners" --paginate 2>"$repo_err")"; then - echo "Repository runner API query succeeded for $REPO" - else - echo "Repository runner API query failed for $REPO; continuing with empty repo runner set" - repo_data='{"runners":[]}' - fi - - if org_data="$(gh api "/orgs/$ORG/actions/runners" --paginate 2>"$org_err")"; then - echo "Organization runner API query succeeded for $ORG" - else - echo "Organization runner API query failed for $ORG; continuing with empty org runner set" - org_data='{"runners":[]}' - fi - - data="$(jq -n --argjson repo "$repo_data" --argjson org "$org_data" '{runners: (($repo.runners // []) + ($org.runners // []) | unique_by(.id))}')" - - repo_count="$(echo "$repo_data" | jq -r '(.runners // []) | length')" - org_count="$(echo "$org_data" | jq -r '(.runners // []) | length')" - merged_count="$(echo "$data" | jq -r '(.runners // []) | length')" - - echo "Runner counts: repo=$repo_count org=$org_count merged=$merged_count" - if [ "$org_count" -eq 0 ] && [ -s "$org_err" ]; then - echo "Org endpoint error output:" - cat "$org_err" - fi - - echo "Discovered self-hosted runners for $REPO (repo+org merged):" - echo "$data" | jq -r '.runners[]? | "- \(.name) | status=\(.status) | busy=\(.busy) | labels=\([.labels[].name] | join(", "))"' - - { - echo "## Runner availability" - echo - echo "Repository: $REPO" - echo "Organization: $ORG" - echo "Counts: repo=$repo_count org=$org_count merged=$merged_count" - echo - echo "Discovered runners (repo+org merged):" - echo "$data" | jq -r '.runners[]? | "- \(.name) | status=\(.status) | busy=\(.busy) | labels=\([.labels[].name] | join(", "))"' - echo - } >> "$GITHUB_STEP_SUMMARY" - - # Define JSON arrays using single quotes so real double-quotes are preserved. - SH_LINUX_X64='["self-hosted","sg-ubuntu-linux"]' - SH_LINUX_ARM='["self-hosted","sg-arm-linux"]' - SH_WINDOWS='["self-hosted","SG-WIN11"]' - SH_MAC='["self-hosted","gv-OSX-Large"]' - FB_LINUX='["ubuntu-latest"]' - FB_LINUX_ARM='["ubuntu-24.04-arm"]' - FB_WINDOWS='["windows-2022"]' - FB_MAC='["macos-latest"]' - - # Returns the self-hosted label array if at least one matching runner - # is online and not busy, otherwise returns the GitHub-hosted fallback. - # Match either runner name or label/tag text, case-insensitively. - pick_runner() { - local label="$1" self_hosted="$2" fallback="$3" - if echo "$data" | jq -e --arg L "$label" \ - '.runners[] - | select(.status=="online" and (.busy|not)) - | select((.name | ascii_downcase) == ($L | ascii_downcase) - or any(.labels[]; (.name | ascii_downcase) == ($L | ascii_downcase)))' \ - >/dev/null 2>&1; then - echo "Selector '$label' matched an available self-hosted runner" >&2 - echo "- $label: self-hosted" >> "$GITHUB_STEP_SUMMARY" - echo "$self_hosted" - else - echo "Selector '$label' did not match an available self-hosted runner" >&2 - echo "- $label: fallback" >> "$GITHUB_STEP_SUMMARY" - echo "$fallback" - fi - } - - echo "linux_x64=$(pick_runner 'sg-ubuntu-linux' "$SH_LINUX_X64" "$FB_LINUX")" >> "$GITHUB_OUTPUT" - echo "linux_arm=$(pick_runner 'sg-arm-linux' "$SH_LINUX_ARM" "$FB_LINUX_ARM")" >> "$GITHUB_OUTPUT" - echo "windows=$(pick_runner 'SG-WIN11' "$SH_WINDOWS" "$FB_WINDOWS")" >> "$GITHUB_OUTPUT" - echo "mac=$(pick_runner 'gv-OSX-Large' "$SH_MAC" "$FB_MAC")" >> "$GITHUB_OUTPUT" - - build: - needs: resolve-runners - runs-on: ${{ fromJson(needs.resolve-runners.outputs[matrix.runner_key]) }} - container: - image: ${{matrix.container}} - credentials: - username: ${{github.actor}} - password: ${{secrets.GNUS_TOKEN_1}} - strategy: - fail-fast: false - matrix: - target: [ Android, iOS, OSX, Linux, Windows ] - build-type: [ Debug, Release ] - abi: [ "" ] - include: - - target: Linux - host: sg-ubuntu-linux - runner_key: linux_x64 - abi: x86_64 - build-type: Debug - container: ghcr.io/geniusventures/debian-bullseye:latest - - target: Linux - host: sg-ubuntu-linux - runner_key: linux_x64 - abi: x86_64 - build-type: Release - container: ghcr.io/geniusventures/debian-bullseye:latest - - target: Linux - host: sg-arm-linux - runner_key: linux_arm - abi: aarch64 - build-type: Debug - container: ghcr.io/geniusventures/debian-bullseye:latest - - target: Linux - host: sg-arm-linux - runner_key: linux_arm - abi: aarch64 - build-type: Release - container: ghcr.io/geniusventures/debian-bullseye:latest - - target: Windows - host: SG-WIN11 - runner_key: windows - - target: OSX - host: gv-OSX-Large - runner_key: mac - - target: iOS - host: gv-OSX-Large - runner_key: mac - - target: Android - host: sg-ubuntu-linux - runner_key: linux_x64 - build-type: Release - abi: arm64-v8a - - target: Android - host: sg-ubuntu-linux - runner_key: linux_x64 - build-type: Release - abi: armeabi-v7a - - target: Android - host: sg-ubuntu-linux - runner_key: linux_x64 - build-type: Debug - abi: arm64-v8a - - target: Android - host: sg-ubuntu-linux - runner_key: linux_x64 - build-type: Debug - abi: armeabi-v7a - exclude: - - target: Android - abi: "" - - target: Linux - abi: "" - steps: - - name: Configure Git Bash on Windows - if: ${{ runner.environment == 'self-hosted' && matrix.target == 'Windows' }} - run: | - $gitBinPath = "C:\Program Files\Git\bin" - - if (Test-Path $gitBinPath) { - Add-Content -Path $env:GITHUB_PATH -Value $gitBinPath - $env:PATH = "$gitBinPath;$env:PATH" - } - - Write-Output "Git Bash configured for bash shell commands" - $bashLocation = (Get-Command bash.exe -ErrorAction SilentlyContinue).Source - if ($bashLocation) { - Write-Output "Bash location: $bashLocation" - } else { - Write-Output "WARNING: bash.exe not found in PATH" - } - - - name: Check if build should run - if: ${{ github.event_name == 'workflow_dispatch' }} - shell: bash - run: | - SHOULD_RUN="true" - # Only check inputs on workflow_dispatch events - if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then - case '${{matrix.target}}-${{matrix.abi}}-${{ matrix.build-type }}' in - Android-arm64-v8a-Release) - if [ '${{ inputs.build_android_arm64v8a_release }}' != 'true' ]; then SHOULD_RUN="false"; fi - ;; - Android-arm64-v8a-Debug) - if [ '${{ inputs.build_android_arm64v8a_debug }}' != 'true' ]; then SHOULD_RUN="false"; fi - ;; - Android-armeabi-v7a-Release) - if [ '${{ inputs.build_android_armv7a_release }}' != 'true' ]; then SHOULD_RUN="false"; fi - ;; - Android-armeabi-v7a-Debug) - if [ '${{ inputs.build_android_armv7a_debug }}' != 'true' ]; then SHOULD_RUN="false"; fi - ;; - iOS-*-Release) - if [ '${{ inputs.build_ios_release }}' != 'true' ]; then SHOULD_RUN="false"; fi - ;; - iOS-*-Debug) - if [ '${{ inputs.build_ios_debug }}' != 'true' ]; then SHOULD_RUN="false"; fi - ;; - OSX-*-Release) - if [ '${{ inputs.build_osx_release }}' != 'true' ]; then SHOULD_RUN="false"; fi - ;; - OSX-*-Debug) - if [ '${{ inputs.build_osx_debug }}' != 'true' ]; then SHOULD_RUN="false"; fi - ;; - Linux-x86_64-Release) - if [ '${{ inputs.build_linux_x86_64_release }}' != 'true' ]; then SHOULD_RUN="false"; fi - ;; - Linux-x86_64-Debug) - if [ '${{ inputs.build_linux_x86_64_debug }}' != 'true' ]; then SHOULD_RUN="false"; fi - ;; - Linux-aarch64-Release) - if [ '${{ inputs.build_linux_aarch64_release }}' != 'true' ]; then SHOULD_RUN="false"; fi - ;; - Linux-aarch64-Debug) - if [ '${{ inputs.build_linux_aarch64_debug }}' != 'true' ]; then SHOULD_RUN="false"; fi - ;; - Windows-*-Release) - if [ '${{ inputs.build_windows_release }}' != 'true' ]; then SHOULD_RUN="false"; fi - ;; - Windows-*-Debug) - if [ '${{ inputs.build_windows_debug }}' != 'true' ]; then SHOULD_RUN="false"; fi - ;; - esac - fi - if [ "$SHOULD_RUN" == "false" ]; then - echo "Skipping build for ${{ matrix.target }} ${{ matrix.abi }} ${{ matrix.build-type }}" - exit 78 - fi - - - name: Clean workspace (self-hosted runners) - if: ${{ runner.environment == 'self-hosted' }} - working-directory: ${{runner.workspace}} - run: | - echo "=== PRE-CLEANUP DEBUG ===" - echo "Current working directory: $(pwd)" - echo "Runner workspace: ${{runner.workspace}}" - echo "GitHub workspace: ${{github.workspace}}" - - # Use sudo on Linux to handle root-owned files left by container jobs - SUDO="" - if [ "$(uname)" = "Linux" ]; then - SUDO="sudo" - fi - - echo "=== CLEANUP ARTIFACTS ===" - # Clean contents of thirdparty directory but keep the directory itself - if [ -d "thirdparty" ]; then - echo "Cleaning thirdparty directory contents..." - $SUDO rm -rf thirdparty/* thirdparty/.* 2>/dev/null || true - echo "thirdparty directory cleaned (kept the directory)" - fi - - echo "=== POST-CLEANUP DEBUG ===" - echo "Runner workspace contents:" - ls -la - if [ -d "thirdparty" ]; then - echo "thirdparty directory exists and contains:" - ls -la thirdparty/ 2>/dev/null || echo " (empty)" - fi - shell: bash - - - name: Checkout - uses: actions/checkout@v6 - with: - # Keep submodule checkout explicit so we can control retries and fetch behavior. - submodules: false - - - name: Harden Git network settings - shell: bash - run: | - # Self-hosted networks/proxies can behave better with HTTP/1.1 for many small fetches. - git config --global http.version HTTP/1.1 - # Reduce concurrent HTTP requests to avoid TLS/socket churn on constrained links. - git config --global http.maxRequests 2 - # Limit nested submodule fetch fanout per job. - git config --global submodule.fetchJobs 8 - - - name: Checkout submodules with retry - shell: bash - run: | - set -euo pipefail - - ATTEMPTS=5 - DELAY=5 - - for attempt in $(seq 1 "$ATTEMPTS"); do - echo "Submodule checkout attempt $attempt/$ATTEMPTS" - git submodule sync --recursive - - if git submodule update --init --recursive --jobs 8; then - echo "Submodule checkout succeeded" - exit 0 - fi - - if [ "$attempt" -lt "$ATTEMPTS" ]; then - echo "Submodule checkout failed; retrying in ${DELAY}s" - sleep "$DELAY" - DELAY=$((DELAY * 2)) - fi - done - - echo "Submodule checkout failed after $ATTEMPTS attempts" - exit 1 - - - name: Configure Linux host - if: ${{ runner.os == 'Linux'}} - run: | - sudo update-alternatives --install /usr/bin/cc cc $(which clang) 100 - sudo update-alternatives --install /usr/bin/c++ c++ $(which clang++) 100 - sudo update-alternatives --set cc $(which clang) - sudo update-alternatives --set c++ $(which clang++) - - sudo apt install libvulkan-dev ninja-build -y - echo "CMAKE_GENERATOR=Ninja" >> $GITHUB_ENV - - - name: Configure macOS host - if: ${{ runner.os == 'macOS'}} - run: | - brew install ninja bash gnu-tar - - # Ensure GNU tar is first in PATH - if [ -d "/opt/homebrew/opt/gnu-tar/libexec/gnubin" ]; then - echo "PATH=/opt/homebrew/opt/gnu-tar/libexec/gnubin:$PATH" >> $GITHUB_ENV - echo "Using GNU tar from /opt/homebrew" - elif [ -d "/usr/local/opt/gnu-tar/libexec/gnubin" ]; then - echo "PATH=/usr/local/opt/gnu-tar/libexec/gnubin:$PATH" >> $GITHUB_ENV - echo "Using GNU tar from /usr/local" - else - echo "WARNING: GNU tar installation not found in expected locations" - echo "Available tar: $(which tar)" - fi - - echo "CMAKE_GENERATOR=Ninja" >> $GITHUB_ENV - - - name: Add Darwin toolchain - if: ${{ matrix.target == 'OSX'}} - run: rustup target add x86_64-apple-darwin - - - name: Add iOS toolchain - if: ${{ matrix.target == 'iOS' }} - run: | - rustup toolchain install nightly-aarch64-apple-darwin - rustup component add rust-src --toolchain nightly-aarch64-apple-darwin - rustup target add aarch64-apple-ios - - - name: Add Android toolchain - if: ${{ matrix.target == 'Android' }} - run: | - NDK_VERSION="r27b" - NDK_DIR="$HOME/android-ndk-$NDK_VERSION" - - if [ ! -d "$NDK_DIR" ]; then - echo "Downloading Android NDK..." - wget https://dl.google.com/android/repository/android-ndk-$NDK_VERSION-linux.zip -O ndk.zip - unzip -o ndk.zip -d $HOME - rm ndk.zip - else - echo "Android NDK already exists at $NDK_DIR, skipping download" - fi - - echo "ANDROID_NDK_HOME=$NDK_DIR" >> $GITHUB_ENV - - rustup target add aarch64-linux-android - rustup target add armv7-linux-androideabi - - - name: Install bindgen - run: cargo install cbindgen - - - name: Add wasm Rust target - run: rustup target add wasm32-unknown-emscripten - - - name: Set build directory - run: | - if [ '${{matrix.abi}}' ]; then - BUILD_DIRECTORY=build/${{matrix.target}}/${{matrix.build-type}}/${{matrix.abi}} - else - BUILD_DIRECTORY=build/${{matrix.target}}/${{matrix.build-type}} - fi - echo "BUILD_DIRECTORY=$BUILD_DIRECTORY" >> $GITHUB_ENV - shell: bash - - - name: Configure CMake for Mac - if: ${{ matrix.target == 'OSX'}} - run: cmake -S build/${{matrix.target}} -B $BUILD_DIRECTORY -DCMAKE_BUILD_TYPE=${{matrix.build-type}} -DPLATFORM=MAC_UNIVERSAL -DSGNS_ENABLE_RELEASE_SYMBOLS=${{ env.SGNS_ENABLE_RELEASE_SYMBOLS }} - - - name: Configure CMake for iOS - if: ${{ matrix.target == 'iOS'}} - run: cmake -S build/${{matrix.target}} -B $BUILD_DIRECTORY -DCMAKE_BUILD_TYPE=${{matrix.build-type}} -DPLATFORM=OS64 -DSGNS_ENABLE_RELEASE_SYMBOLS=${{ env.SGNS_ENABLE_RELEASE_SYMBOLS }} - - - name: Configure CMake for Android - if: ${{ matrix.target == 'Android'}} - run: cmake -S build/${{matrix.target}} -B $BUILD_DIRECTORY -DCMAKE_BUILD_TYPE=${{matrix.build-type}} -DANDROID_ABI=${{matrix.abi}} -DSGNS_ENABLE_RELEASE_SYMBOLS=${{ env.SGNS_ENABLE_RELEASE_SYMBOLS }} - - - name: Configure CMake for Windows - if: ${{ matrix.target == 'Windows' }} - run: cmake -S build/${{matrix.target}} -B $env:BUILD_DIRECTORY -DCMAKE_BUILD_TYPE=${{matrix.build-type}} -DSGNS_ENABLE_RELEASE_SYMBOLS=${{ env.SGNS_ENABLE_RELEASE_SYMBOLS }} - - - name: Configure CMake for Linux - if: ${{ matrix.target == 'Linux' }} - run: cmake -S build/${{matrix.target}} -B $BUILD_DIRECTORY -DCMAKE_BUILD_TYPE=${{matrix.build-type}} -DSGNS_ENABLE_RELEASE_SYMBOLS=${{ env.SGNS_ENABLE_RELEASE_SYMBOLS }} - - - name: Build thirdparty - working-directory: ${{env.BUILD_DIRECTORY}} - run: cmake --build . --config ${{matrix.build-type}} -j - - - name: Compress directories - if: github.ref_name == 'main' || github.ref_name == 'develop' || (github.event_name == 'workflow_dispatch' && github.event.inputs.tag != '') - working-directory: ${{env.BUILD_DIRECTORY}} - shell: bash - run: | - if [ '${{matrix.abi}}' ]; then - FILE_NAME="${{matrix.target}}-${{matrix.abi}}-${{matrix.build-type}}.tar.gz" - else - FILE_NAME="${{matrix.target}}-${{matrix.build-type}}.tar.gz" - fi - - echo "FILE_NAME=$FILE_NAME" >> $GITHUB_ENV - - tar --no-wildcards-match-slash --exclude='./*/src' --exclude='./*/tmp' --transform='s|^\.|${{env.BUILD_DIRECTORY}}|g' -czf $FILE_NAME ./*/ - - - name: Set release tag - shell: bash - run: | - if ${{ github.event_name == 'workflow_dispatch' }} && [ '${{ github.event.inputs.tag }}' ]; then - RELEASE_TAG="${{ github.event.inputs.tag }}" - IS_TAG_RELEASE="true" - else - if [ '${{matrix.abi}}' ]; then - RELEASE_TAG="${{ matrix.target }}-${{matrix.abi}}-${{ github.ref_name }}-${{ matrix.build-type }}" - else - RELEASE_TAG="${{ matrix.target }}-${{ github.ref_name }}-${{ matrix.build-type }}" - fi - IS_TAG_RELEASE="false" - fi - - echo "RELEASE_TAG=$RELEASE_TAG" >> $GITHUB_ENV - echo "IS_TAG_RELEASE=$IS_TAG_RELEASE" >> $GITHUB_ENV - - - name: Create release tag - if: github.ref_name == 'main' || github.ref_name == 'develop' || (github.event_name == 'workflow_dispatch' && github.event.inputs.tag != '') - shell: bash - id: create-release-tag - run: | - echo "Checking if release $RELEASE_TAG exists..." - - if [ "$IS_TAG_RELEASE" = "true" ]; then - # For explicit tags, all matrix jobs share the same release tag. - # Create once if missing; concurrent creators should not fail the job. - if gh release view "$RELEASE_TAG" >/dev/null 2>&1; then - echo "Release $RELEASE_TAG already exists; skipping create." - else - echo "Release does not exist yet; creating tag/release for $RELEASE_TAG..." - git tag "$RELEASE_TAG" "${{ github.sha }}" || true - git push origin "$RELEASE_TAG" || true - - if ! gh release create "$RELEASE_TAG" \ - --target "${{ github.sha }}" \ - -t "$RELEASE_TAG" \ - -n "Tag: $RELEASE_TAG | SHA: ${{ github.sha }}"; then - if gh release view "$RELEASE_TAG" >/dev/null 2>&1; then - echo "Release was created by another matrix job; continuing." - else - echo "Failed to create release $RELEASE_TAG for an unexpected reason." - exit 1 - fi - fi - fi - else - if gh release view "$RELEASE_TAG" >/dev/null 2>&1; then - echo "Deleting existing release/tag $RELEASE_TAG..." - gh release delete "$RELEASE_TAG" --yes || true - git push origin ":refs/tags/$RELEASE_TAG" || true - git tag -d "$RELEASE_TAG" || true - fi - - echo "Creating new tag $RELEASE_TAG..." - git tag -f "$RELEASE_TAG" "${{ github.sha }}" - git push origin "$RELEASE_TAG" --force - - echo "Creating GitHub release $RELEASE_TAG..." - gh release create "$RELEASE_TAG" \ - --target "${{ github.sha }}" \ - -t "${{ matrix.target }} ${{ github.ref_name }} ${{ matrix.build-type }} build" \ - -n "Branch: ${{ github.ref_name }} | SHA: ${{ github.sha }}" \ - --prerelease - fi - - - name: Upload file - if: github.ref_name == 'main' || github.ref_name == 'develop' || (github.event_name == 'workflow_dispatch' && github.event.inputs.tag != '') - working-directory: ${{env.BUILD_DIRECTORY}} - run: gh release upload ${{env.RELEASE_TAG}} ${{env.FILE_NAME}} --clobber +name: Multiplatform build and upload + +on: + pull_request: + workflow_dispatch: + inputs: + tag: + description: "Release tag" + required: false + type: string + build_android_arm64v8a_release: + description: 'Build Android arm64-v8a Release' + required: true + default: true + type: boolean + build_android_arm64v8a_debug: + description: 'Build Android arm64-v8a Debug' + required: true + default: true + type: boolean + build_android_armv7a_release: + description: 'Build Android armeabi-v7a Release' + required: true + default: true + type: boolean + build_android_armv7a_debug: + description: 'Build Android armeabi-v7a Debug' + required: true + default: true + type: boolean + build_ios_release: + description: 'Build iOS Release' + required: true + default: true + type: boolean + build_ios_debug: + description: 'Build iOS Debug' + required: true + default: true + type: boolean + build_osx_release: + description: 'Build OSX Release' + required: true + default: true + type: boolean + build_osx_debug: + description: 'Build OSX Debug' + required: true + default: true + type: boolean + build_linux_x86_64_release: + description: 'Build Linux x86_64 Release' + required: true + default: true + type: boolean + build_linux_x86_64_debug: + description: 'Build Linux x86_64 Debug' + required: true + default: true + type: boolean + build_linux_aarch64_release: + description: 'Build Linux aarch64 Release' + required: true + default: true + type: boolean + build_linux_aarch64_debug: + description: 'Build Linux aarch64 Debug' + required: true + default: true + type: boolean + build_windows_release: + description: 'Build Windows Release' + required: true + default: true + type: boolean + build_windows_debug: + description: 'Build Windows Debug' + required: true + default: true + type: boolean + sgns_enable_release_symbols: + description: 'Enable SGNS release symbols in CMake configure' + required: true + default: false + type: boolean + +permissions: + contents: read + packages: read + +jobs: + prepare: + name: Generate build matrix + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.gen.outputs.matrix }} + steps: + - name: Generate build matrix + id: gen + env: + GATED: ${{ github.event_name == 'workflow_dispatch' }} + BUILD_ANDROID_ARM64V8A_RELEASE: ${{ inputs.build_android_arm64v8a_release }} + BUILD_ANDROID_ARM64V8A_DEBUG: ${{ inputs.build_android_arm64v8a_debug }} + BUILD_ANDROID_ARMV7A_RELEASE: ${{ inputs.build_android_armv7a_release }} + BUILD_ANDROID_ARMV7A_DEBUG: ${{ inputs.build_android_armv7a_debug }} + BUILD_IOS_RELEASE: ${{ inputs.build_ios_release }} + BUILD_IOS_DEBUG: ${{ inputs.build_ios_debug }} + BUILD_OSX_RELEASE: ${{ inputs.build_osx_release }} + BUILD_OSX_DEBUG: ${{ inputs.build_osx_debug }} + BUILD_LINUX_X86_64_RELEASE: ${{ inputs.build_linux_x86_64_release }} + BUILD_LINUX_X86_64_DEBUG: ${{ inputs.build_linux_x86_64_debug }} + BUILD_LINUX_AARCH64_RELEASE: ${{ inputs.build_linux_aarch64_release }} + BUILD_LINUX_AARCH64_DEBUG: ${{ inputs.build_linux_aarch64_debug }} + BUILD_WINDOWS_RELEASE: ${{ inputs.build_windows_release }} + BUILD_WINDOWS_DEBUG: ${{ inputs.build_windows_debug }} + run: | + set -euo pipefail + + # One entry per supported target/ABI/build-type combination. + # `toggle` names the workflow_dispatch input that enables the entry; + # it is stripped before the matrix is handed to the build workflow. + MATRIX='[ + {"target":"Android","build-type":"Release","abi":"arm64-v8a","runner_key":"linux_x64","toggle":"BUILD_ANDROID_ARM64V8A_RELEASE"}, + {"target":"Android","build-type":"Debug","abi":"arm64-v8a","runner_key":"linux_x64","toggle":"BUILD_ANDROID_ARM64V8A_DEBUG"}, + {"target":"Android","build-type":"Release","abi":"armeabi-v7a","runner_key":"linux_x64","toggle":"BUILD_ANDROID_ARMV7A_RELEASE"}, + {"target":"Android","build-type":"Debug","abi":"armeabi-v7a","runner_key":"linux_x64","toggle":"BUILD_ANDROID_ARMV7A_DEBUG"}, + {"target":"iOS","build-type":"Release","abi":"","runner_key":"mac","toggle":"BUILD_IOS_RELEASE"}, + {"target":"iOS","build-type":"Debug","abi":"","runner_key":"mac","toggle":"BUILD_IOS_DEBUG"}, + {"target":"OSX","build-type":"Release","abi":"","runner_key":"mac","toggle":"BUILD_OSX_RELEASE"}, + {"target":"OSX","build-type":"Debug","abi":"","runner_key":"mac","toggle":"BUILD_OSX_DEBUG"}, + {"target":"Linux","build-type":"Release","abi":"x86_64","runner_key":"linux_x64","toggle":"BUILD_LINUX_X86_64_RELEASE","container":"ghcr.io/geniusventures/debian-bullseye:latest"}, + {"target":"Linux","build-type":"Debug","abi":"x86_64","runner_key":"linux_x64","toggle":"BUILD_LINUX_X86_64_DEBUG","container":"ghcr.io/geniusventures/debian-bullseye:latest"}, + {"target":"Linux","build-type":"Release","abi":"aarch64","runner_key":"linux_arm","toggle":"BUILD_LINUX_AARCH64_RELEASE","container":"ghcr.io/geniusventures/debian-bullseye:latest"}, + {"target":"Linux","build-type":"Debug","abi":"aarch64","runner_key":"linux_arm","toggle":"BUILD_LINUX_AARCH64_DEBUG","container":"ghcr.io/geniusventures/debian-bullseye:latest"}, + {"target":"Windows","build-type":"Release","abi":"","runner_key":"windows","toggle":"BUILD_WINDOWS_RELEASE"}, + {"target":"Windows","build-type":"Debug","abi":"","runner_key":"windows","toggle":"BUILD_WINDOWS_DEBUG"} + ]' + + # On workflow_dispatch, drop the combinations whose toggle was unchecked. + if [ "$GATED" = "true" ]; then + MATRIX=$(jq -c '[ .[] | select((env[.toggle] // "false") == "true") ]' <<<"$MATRIX") + fi + + # The build workflow's strategy consumes the canonical {include: [...]} form. + MATRIX=$(jq -c '{include: [.[] | del(.toggle)]}' <<<"$MATRIX") + + COUNT=$(jq '.include | length' <<<"$MATRIX") + echo "Building $COUNT combinations:" + jq -r '.include[] | "- \(.target) \(.abi) \(.["build-type"])"' <<<"$MATRIX" + + if [ "$COUNT" -eq 0 ]; then + echo "No target combinations enabled; nothing to build." >&2 + exit 1 + fi + + echo "matrix=$MATRIX" >> "$GITHUB_OUTPUT" + + build: + name: Build and upload + needs: prepare + permissions: + contents: write + packages: read + uses: ./.github/workflows/build.yml + with: + matrix: ${{ needs.prepare.outputs.matrix }} + upload: ${{ github.ref_name == 'main' || github.ref_name == 'develop' || inputs.tag != '' }} + release-tag: ${{ inputs.tag }} + sgns_enable_release_symbols: ${{ inputs.sgns_enable_release_symbols }} + secrets: inherit diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ba482a8b..5d42a378 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,14 +1,151 @@ -name: Build +name: Build thirdparty +# Reusable build engine. Callers pass the matrix of target/ABI/build-type +# combinations to build (see build-targets.yml for how it is generated). on: - pull_request: - workflow_dispatch: + workflow_call: + inputs: + matrix: + description: "JSON array of builds: {target, build-type, abi, runner_key, container?}" + required: true + type: string + upload: + description: "Upload build artifacts to a GitHub release" + required: false + default: false + type: boolean + release-tag: + description: "Shared release tag (when empty, per-target tags are derived from the branch)" + required: false + default: "" + type: string + sgns_enable_release_symbols: + description: "Enable SGNS release symbols in CMake configure" + required: false + default: false + type: boolean + permissions: contents: read packages: read + +env: + GH_TOKEN: ${{ secrets.GNUS_TOKEN_1 }} + SGNS_ENABLE_RELEASE_SYMBOLS: ${{ inputs.sgns_enable_release_symbols && 'ON' || 'OFF' }} + jobs: + resolve-runners: + runs-on: ubuntu-latest + outputs: + linux_x64: ${{ steps.pick.outputs.linux_x64 }} + linux_arm: ${{ steps.pick.outputs.linux_arm }} + windows: ${{ steps.pick.outputs.windows }} + mac: ${{ steps.pick.outputs.mac }} + matrix: ${{ steps.matrix.outputs.matrix }} + steps: + - name: Check self-hosted runner availability + id: pick + env: + REPO: ${{ github.repository }} + run: | + set -euo pipefail + ORG="${REPO%%/*}" + repo_err="$(mktemp)" + org_err="$(mktemp)" + + # Some org-scoped runners may not show up via the repo endpoint for this token. + # Query both scopes and merge the results. + if repo_data="$(gh api "/repos/$REPO/actions/runners" --paginate 2>"$repo_err")"; then + echo "Repository runner API query succeeded for $REPO" + else + echo "Repository runner API query failed for $REPO; continuing with empty repo runner set" + repo_data='{"runners":[]}' + fi + + if org_data="$(gh api "/orgs/$ORG/actions/runners" --paginate 2>"$org_err")"; then + echo "Organization runner API query succeeded for $ORG" + else + echo "Organization runner API query failed for $ORG; continuing with empty org runner set" + org_data='{"runners":[]}' + fi + + data="$(jq -n --argjson repo "$repo_data" --argjson org "$org_data" '{runners: (($repo.runners // []) + ($org.runners // []) | unique_by(.id))}')" + + repo_count="$(echo "$repo_data" | jq -r '(.runners // []) | length')" + org_count="$(echo "$org_data" | jq -r '(.runners // []) | length')" + merged_count="$(echo "$data" | jq -r '(.runners // []) | length')" + + echo "Runner counts: repo=$repo_count org=$org_count merged=$merged_count" + if [ "$org_count" -eq 0 ] && [ -s "$org_err" ]; then + echo "Org endpoint error output:" + cat "$org_err" + fi + + echo "Discovered self-hosted runners for $REPO (repo+org merged):" + echo "$data" | jq -r '.runners[]? | "- \(.name) | status=\(.status) | busy=\(.busy) | labels=\([.labels[].name] | join(", "))"' + + { + echo "## Runner availability" + echo + echo "Repository: $REPO" + echo "Organization: $ORG" + echo "Counts: repo=$repo_count org=$org_count merged=$merged_count" + echo + echo "Discovered runners (repo+org merged):" + echo "$data" | jq -r '.runners[]? | "- \(.name) | status=\(.status) | busy=\(.busy) | labels=\([.labels[].name] | join(", "))"' + echo + } >> "$GITHUB_STEP_SUMMARY" + + # Define JSON arrays using single quotes so real double-quotes are preserved. + SH_LINUX_X64='["self-hosted","sg-ubuntu-linux"]' + SH_LINUX_ARM='["self-hosted","sg-arm-linux"]' + SH_WINDOWS='["self-hosted","SG-WIN11"]' + SH_MAC='["self-hosted","gv-OSX-Large"]' + FB_LINUX='["ubuntu-latest"]' + FB_LINUX_ARM='["ubuntu-24.04-arm"]' + FB_WINDOWS='["windows-2022"]' + FB_MAC='["macos-latest"]' + + # Returns the self-hosted label array if at least one matching runner + # is online and not busy, otherwise returns the GitHub-hosted fallback. + # Match either runner name or label/tag text, case-insensitively. + pick_runner() { + local label="$1" self_hosted="$2" fallback="$3" + if echo "$data" | jq -e --arg L "$label" \ + '.runners[] + | select(.status=="online" and (.busy|not)) + | select((.name | ascii_downcase) == ($L | ascii_downcase) + or any(.labels[]; (.name | ascii_downcase) == ($L | ascii_downcase)))' \ + >/dev/null 2>&1; then + echo "Selector '$label' matched an available self-hosted runner" >&2 + echo "- $label: self-hosted" >> "$GITHUB_STEP_SUMMARY" + echo "$self_hosted" + else + echo "Selector '$label' did not match an available self-hosted runner" >&2 + echo "- $label: fallback" >> "$GITHUB_STEP_SUMMARY" + echo "$fallback" + fi + } + + echo "linux_x64=$(pick_runner 'sg-ubuntu-linux' "$SH_LINUX_X64" "$FB_LINUX")" >> "$GITHUB_OUTPUT" + echo "linux_arm=$(pick_runner 'sg-arm-linux' "$SH_LINUX_ARM" "$FB_LINUX_ARM")" >> "$GITHUB_OUTPUT" + echo "windows=$(pick_runner 'SG-WIN11' "$SH_WINDOWS" "$FB_WINDOWS")" >> "$GITHUB_OUTPUT" + echo "mac=$(pick_runner 'gv-OSX-Large' "$SH_MAC" "$FB_MAC")" >> "$GITHUB_OUTPUT" + + # Forward the caller-provided matrix through a job output so the build + # job's strategy can read it from the needs context. + - name: Forward build matrix + id: matrix + env: + BUILD_MATRIX: ${{ inputs.matrix }} + run: echo "matrix=$BUILD_MATRIX" >> "$GITHUB_OUTPUT" + build: - runs-on: ${{matrix.host}} + needs: resolve-runners + permissions: + contents: write + packages: read + runs-on: ${{ fromJson(needs.resolve-runners.outputs[matrix.runner_key]) }} container: image: ${{matrix.container}} credentials: @@ -16,40 +153,7 @@ jobs: password: ${{secrets.GNUS_TOKEN_1}} strategy: fail-fast: false - matrix: - target: [ Android, iOS, OSX, Linux, Windows ] - build-type: [ Release ] - abi: [ "" ] - include: - - target: Linux - host: sg-ubuntu-linux - abi: x86_64 - build-type: Release - container: ghcr.io/geniusventures/debian-bullseye:latest - - target: Linux - host: sg-arm-linux - abi: aarch64 - build-type: Release - container: ghcr.io/geniusventures/debian-bullseye:latest - - target: Windows - host: SG-WIN11 - - target: OSX - host: gv-OSX-Large - - target: iOS - host: gv-OSX-Large - - target: Android - host: sg-ubuntu-linux - build-type: Release - abi: arm64-v8a - - target: Android - host: sg-ubuntu-linux - build-type: Release - abi: armeabi-v7a - exclude: - - target: Android - abi: "" - - target: Linux - abi: "" + matrix: ${{ fromJson(needs.resolve-runners.outputs.matrix) }} steps: - name: Configure Git Bash on Windows if: ${{ runner.environment == 'self-hosted' && matrix.target == 'Windows' }} @@ -60,7 +164,7 @@ jobs: Add-Content -Path $env:GITHUB_PATH -Value $gitBinPath $env:PATH = "$gitBinPath;$env:PATH" } - + Write-Output "Git Bash configured for bash shell commands" $bashLocation = (Get-Command bash.exe -ErrorAction SilentlyContinue).Source if ($bashLocation) { @@ -75,23 +179,23 @@ jobs: run: | echo "=== PRE-CLEANUP DEBUG ===" echo "Current working directory: $(pwd)" - echo "Runner workspace: ${RUNNER_WORKSPACE}" + echo "Runner workspace: ${{runner.workspace}}" echo "GitHub workspace: ${{github.workspace}}" - + # Use sudo on Linux to handle root-owned files left by container jobs SUDO="" if [ "$(uname)" = "Linux" ]; then SUDO="sudo" fi - echo "=== CLEANUP ARTIFACTS ===" + echo "=== CLEANUP ARTIFACTS ===" # Clean contents of thirdparty directory but keep the directory itself if [ -d "thirdparty" ]; then echo "Cleaning thirdparty directory contents..." $SUDO rm -rf thirdparty/* thirdparty/.* 2>/dev/null || true echo "thirdparty directory cleaned (kept the directory)" fi - + echo "=== POST-CLEANUP DEBUG ===" echo "Runner workspace contents:" ls -la @@ -100,16 +204,49 @@ jobs: ls -la thirdparty/ 2>/dev/null || echo " (empty)" fi shell: bash - env: - RUNNER_WORKSPACE: ${{runner.workspace}} - name: Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + uses: actions/checkout@v6 with: - persist-credentials: false + # Keep submodule checkout explicit so we can control retries and fetch behavior. + submodules: false + + - name: Harden Git network settings + shell: bash + run: | + # Self-hosted networks/proxies can behave better with HTTP/1.1 for many small fetches. + git config --global http.version HTTP/1.1 + # Reduce concurrent HTTP requests to avoid TLS/socket churn on constrained links. + git config --global http.maxRequests 2 + # Limit nested submodule fetch fanout per job. + git config --global submodule.fetchJobs 8 - - name: Parallel checkout submodules - run: git submodule update --init --recursive --jobs 4 --depth 1 + - name: Checkout submodules with retry + shell: bash + run: | + set -euo pipefail + + ATTEMPTS=5 + DELAY=5 + + for attempt in $(seq 1 "$ATTEMPTS"); do + echo "Submodule checkout attempt $attempt/$ATTEMPTS" + git submodule sync --recursive + + if git submodule update --init --recursive --jobs 8; then + echo "Submodule checkout succeeded" + exit 0 + fi + + if [ "$attempt" -lt "$ATTEMPTS" ]; then + echo "Submodule checkout failed; retrying in ${DELAY}s" + sleep "$DELAY" + DELAY=$((DELAY * 2)) + fi + done + + echo "Submodule checkout failed after $ATTEMPTS attempts" + exit 1 - name: Configure Linux host if: ${{ runner.os == 'Linux'}} @@ -157,7 +294,7 @@ jobs: run: | NDK_VERSION="r27b" NDK_DIR="$HOME/android-ndk-$NDK_VERSION" - + if [ ! -d "$NDK_DIR" ]; then echo "Downloading Android NDK..." wget https://dl.google.com/android/repository/android-ndk-$NDK_VERSION-linux.zip -O ndk.zip @@ -190,24 +327,111 @@ jobs: - name: Configure CMake for Mac if: ${{ matrix.target == 'OSX'}} - run: cmake -S build/${{matrix.target}} -B $BUILD_DIRECTORY -DCMAKE_BUILD_TYPE=${{matrix.build-type}} -DPLATFORM=MAC_UNIVERSAL + run: cmake -S build/${{matrix.target}} -B $BUILD_DIRECTORY -DCMAKE_BUILD_TYPE=${{matrix.build-type}} -DPLATFORM=MAC_UNIVERSAL -DSGNS_ENABLE_RELEASE_SYMBOLS=${{ env.SGNS_ENABLE_RELEASE_SYMBOLS }} - name: Configure CMake for iOS if: ${{ matrix.target == 'iOS'}} - run: cmake -S build/${{matrix.target}} -B $BUILD_DIRECTORY -DCMAKE_BUILD_TYPE=${{matrix.build-type}} -DPLATFORM=OS64 + run: cmake -S build/${{matrix.target}} -B $BUILD_DIRECTORY -DCMAKE_BUILD_TYPE=${{matrix.build-type}} -DPLATFORM=OS64 -DSGNS_ENABLE_RELEASE_SYMBOLS=${{ env.SGNS_ENABLE_RELEASE_SYMBOLS }} - name: Configure CMake for Android if: ${{ matrix.target == 'Android'}} - run: cmake -S build/${{matrix.target}} -B $BUILD_DIRECTORY -DCMAKE_BUILD_TYPE=${{matrix.build-type}} -DANDROID_ABI=${{matrix.abi}} + run: cmake -S build/${{matrix.target}} -B $BUILD_DIRECTORY -DCMAKE_BUILD_TYPE=${{matrix.build-type}} -DANDROID_ABI=${{matrix.abi}} -DSGNS_ENABLE_RELEASE_SYMBOLS=${{ env.SGNS_ENABLE_RELEASE_SYMBOLS }} - name: Configure CMake for Windows if: ${{ matrix.target == 'Windows' }} - run: cmake -S build/${{matrix.target}} -B $env:BUILD_DIRECTORY -DCMAKE_BUILD_TYPE=${{matrix.build-type}} + run: cmake -S build/${{matrix.target}} -B $env:BUILD_DIRECTORY -DCMAKE_BUILD_TYPE=${{matrix.build-type}} -DSGNS_ENABLE_RELEASE_SYMBOLS=${{ env.SGNS_ENABLE_RELEASE_SYMBOLS }} - name: Configure CMake for Linux if: ${{ matrix.target == 'Linux' }} - run: cmake -S build/${{matrix.target}} -B $BUILD_DIRECTORY -DCMAKE_BUILD_TYPE=${{matrix.build-type}} + run: cmake -S build/${{matrix.target}} -B $BUILD_DIRECTORY -DCMAKE_BUILD_TYPE=${{matrix.build-type}} -DSGNS_ENABLE_RELEASE_SYMBOLS=${{ env.SGNS_ENABLE_RELEASE_SYMBOLS }} - name: Build thirdparty working-directory: ${{env.BUILD_DIRECTORY}} run: cmake --build . --config ${{matrix.build-type}} -j + + - name: Compress directories + if: ${{ inputs.upload }} + working-directory: ${{env.BUILD_DIRECTORY}} + shell: bash + run: | + if [ '${{matrix.abi}}' ]; then + FILE_NAME="${{matrix.target}}-${{matrix.abi}}-${{matrix.build-type}}.tar.gz" + else + FILE_NAME="${{matrix.target}}-${{matrix.build-type}}.tar.gz" + fi + + echo "FILE_NAME=$FILE_NAME" >> $GITHUB_ENV + + tar --no-wildcards-match-slash --exclude='./*/src' --exclude='./*/tmp' --transform='s|^\.|${{env.BUILD_DIRECTORY}}|g' -czf $FILE_NAME ./*/ + + - name: Set release tag + shell: bash + run: | + if [ -n '${{ inputs.release-tag }}' ]; then + RELEASE_TAG="${{ inputs.release-tag }}" + IS_TAG_RELEASE="true" + else + if [ '${{matrix.abi}}' ]; then + RELEASE_TAG="${{ matrix.target }}-${{matrix.abi}}-${{ github.ref_name }}-${{ matrix.build-type }}" + else + RELEASE_TAG="${{ matrix.target }}-${{ github.ref_name }}-${{ matrix.build-type }}" + fi + IS_TAG_RELEASE="false" + fi + + echo "RELEASE_TAG=$RELEASE_TAG" >> $GITHUB_ENV + echo "IS_TAG_RELEASE=$IS_TAG_RELEASE" >> $GITHUB_ENV + + - name: Create release tag + if: ${{ inputs.upload }} + shell: bash + id: create-release-tag + run: | + echo "Checking if release $RELEASE_TAG exists..." + + if [ "$IS_TAG_RELEASE" = "true" ]; then + # For explicit tags, all matrix jobs share the same release tag. + # Create once if missing; concurrent creators should not fail the job. + if gh release view "$RELEASE_TAG" >/dev/null 2>&1; then + echo "Release $RELEASE_TAG already exists; skipping create." + else + echo "Release does not exist yet; creating tag/release for $RELEASE_TAG..." + git tag "$RELEASE_TAG" "${{ github.sha }}" || true + git push origin "$RELEASE_TAG" || true + + if ! gh release create "$RELEASE_TAG" \ + --target "${{ github.sha }}" \ + -t "$RELEASE_TAG" \ + -n "Tag: $RELEASE_TAG | SHA: ${{ github.sha }}"; then + if gh release view "$RELEASE_TAG" >/dev/null 2>&1; then + echo "Release was created by another matrix job; continuing." + else + echo "Failed to create release $RELEASE_TAG for an unexpected reason." + exit 1 + fi + fi + fi + else + if gh release view "$RELEASE_TAG" >/dev/null 2>&1; then + echo "Deleting existing release/tag $RELEASE_TAG..." + gh release delete "$RELEASE_TAG" --yes || true + git push origin ":refs/tags/$RELEASE_TAG" || true + git tag -d "$RELEASE_TAG" || true + fi + + echo "Creating new tag $RELEASE_TAG..." + git tag -f "$RELEASE_TAG" "${{ github.sha }}" + git push origin "$RELEASE_TAG" --force + + echo "Creating GitHub release $RELEASE_TAG..." + gh release create "$RELEASE_TAG" \ + --target "${{ github.sha }}" \ + -t "${{ matrix.target }} ${{ github.ref_name }} ${{ matrix.build-type }} build" \ + -n "Branch: ${{ github.ref_name }} | SHA: ${{ github.sha }}" \ + --prerelease + fi + + - name: Upload file + if: ${{ inputs.upload }} + working-directory: ${{env.BUILD_DIRECTORY}} + run: gh release upload ${{env.RELEASE_TAG}} ${{env.FILE_NAME}} --clobber diff --git a/.github/workflows/setup-windows-runner.yml b/.github/workflows/setup-windows-runner.yml deleted file mode 100644 index f58d93ee..00000000 --- a/.github/workflows/setup-windows-runner.yml +++ /dev/null @@ -1,69 +0,0 @@ -name: Setup Windows Self-Hosted Runner - -on: - workflow_dispatch: -permissions: - contents: read -jobs: - setup: - runs-on: SG-WIN11 - steps: - - name: Check Rust environment - run: | - Write-Host "=== Rust Environment Check ===" - Write-Host "RUSTUP_HOME: $env:RUSTUP_HOME" - Write-Host "CARGO_HOME: $env:CARGO_HOME" - Write-Host "" - Write-Host "=== PATH ===" - $env:PATH -split ';' | ForEach-Object { Write-Host $_ } - Write-Host "" - Write-Host "=== Cargo bin directory contents ===" - if (Test-Path "$env:CARGO_HOME\bin") { - Get-ChildItem "$env:CARGO_HOME\bin" | Select-Object Name - } else { - Write-Host "CARGO_HOME\bin does not exist" - } - if (Test-Path "$env:USERPROFILE\.cargo\bin") { - Write-Host "" - Write-Host "=== USERPROFILE\.cargo\bin contents ===" - Get-ChildItem "$env:USERPROFILE\.cargo\bin" | Select-Object Name - } - Write-Host "" - Write-Host "=== Command availability ===" - Write-Host "cargo: $(Get-Command cargo -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Source)" - Write-Host "rustup: $(Get-Command rustup -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Source)" - Write-Host "cbindgen: $(Get-Command cbindgen -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Source)" - shell: powershell - - - name: Install cbindgen - run: | - Write-Host "=== Installing cbindgen ===" - cargo install cbindgen - Write-Host "" - Write-Host "=== Checking cbindgen.exe permissions ===" - icacls "C:\Rust\cargo\bin\cbindgen.exe" - Write-Host "" - Write-Host "=== Checking cargo.exe permissions for comparison ===" - icacls "C:\Rust\cargo\bin\cargo.exe" - Write-Host "" - Write-Host "=== Checking for deny rules ===" - $acl = Get-Acl "C:\Rust\cargo\bin\cbindgen.exe" - Write-Host "Owner: $($acl.Owner)" - Write-Host "Access Rules:" - $acl.Access | Format-Table IdentityReference, FileSystemRights, AccessControlType, IsInherited -AutoSize - Write-Host "" - Write-Host "=== Trying to run cbindgen as NETWORK SERVICE ===" - Write-Host "Current user: $env:USERNAME" - Write-Host "User identity: $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name)" - shell: powershell - - - name: Check cbindgen after install - run: | - Write-Host "=== After cbindgen install ===" - Write-Host "cbindgen location: $(Get-Command cbindgen -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Source)" - cbindgen --version - shell: powershell - - - name: Install wasm Rust target - run: rustup target add wasm32-unknown-emscripten - shell: powershell diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml deleted file mode 100644 index 7b0c40b9..00000000 --- a/.github/workflows/test-build.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: Multiplatform build - -on: - workflow_dispatch: -permissions: - contents: read - packages: read -jobs: - android-debug: - uses: ./.github/workflows/build.yml - with: - target: Android - build-type: Debug - abi: arm64 - ios-debug: - uses: ./.github/workflows/build.yml - with: - target: iOS - build-type: Debug - linux-debug: - uses: ./.github/workflows/build.yml - with: - target: Linux - build-type: Debug - macos-debug: - uses: ./.github/workflows/build.yml - with: - target: OSX - build-type: Debug - windows-debug: - uses: ./.github/workflows/build.yml - with: - target: Windows - build-type: Debug - android-release: - uses: ./.github/workflows/build.yml - with: - target: Android - build-type: Release - abi: arm64 - ios-release: - uses: ./.github/workflows/build.yml - with: - target: iOS - build-type: Release - linux-release: - uses: ./.github/workflows/build.yml - with: - target: Linux - build-type: Release - macos-release: - uses: ./.github/workflows/build.yml - with: - target: OSX - build-type: Release - windows-release: - uses: ./.github/workflows/build.yml - with: - target: Windows - build-type: Release diff --git a/AGENTS.md b/AGENTS.md index 9aba059f..810ae558 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -21,7 +21,7 @@ ## Critical developer workflows (repo-specific) - Initialize submodules before any build: ```bash -git submodule update --init --recursive --jobs 4 --depth 1 +git submodule update --init --recursive --depth 1 ``` - Preferred configure/build pattern (matches README and CI): ```bash @@ -31,7 +31,7 @@ ninja ``` - macOS uses `-DPLATFORM=MAC_UNIVERSAL` in CI (`.github/workflows/build.yml`). - iOS uses `-DPLATFORM=OS64`; Android requires `-DANDROID_ABI=` and `ANDROID_NDK_HOME`. -- Linux CI forces clang via `update-alternatives`; do not assume gcc parity without checking. +- Linux CI forces clang via `update-alternatives`; do not assume GCC parity without checking. ## CI and release integration points - Main validation matrix: `.github/workflows/build.yml` (Android/iOS/OSX/Linux/Windows). @@ -47,4 +47,3 @@ ninja - Make minimal, surgical changes in the relevant platform file and/or `build/CommonTargets.CMake`; avoid broad refactors across vendored sources. - When adding a dependency, update both `DEPENDS` and required `*_DIR`/include cache args for downstream consumers. - Validate changes by mirroring one CI configure/build path for the affected platform. - diff --git a/README.md b/README.md index 2a2fea41..961e46e7 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,10 @@ -This is the repository for third party of [SuperGenius](https://github.com/GeniusVentures/SuperGenius/). +# thirdparty -![Android](https://github.com/GeniusVentures/thirdparty/actions/workflows/Android.yml/badge.svg?branch=master) -![iOS](https://github.com/GeniusVentures/thirdparty/actions/workflows/iOS.yml/badge.svg?branch=master) -![Linux](https://github.com/GeniusVentures/thirdparty/actions/workflows/Linux.yml/badge.svg?branch=master) -![macOS](https://github.com/GeniusVentures/thirdparty/actions/workflows/macOS.yml/badge.svg?branch=master) -![Windows](https://github.com/GeniusVentures/thirdparty/actions/workflows/Windows.yml/badge.svg?branch=master) +This is the repository for third party of [SuperGenius](https://github.com/GeniusVentures/SuperGenius/). -=================================== +![Multiplatform build and upload](https://github.com/GeniusVentures/thirdparty/actions/workflows/build-targets.yml/badge.svg?branch=master) -# Download pre-built libraries +## Download pre-built libraries Pre-built libraries are available on the [release page](https://github.com/GeniusVentures/thirdparty/releases). The tags are named with the following convention: @@ -21,11 +17,11 @@ Where: The `master` branch has the release versions, for development download from the `develop` branch to get the newest builds. -# Building +## Building If you want to build `thirdparty` for yourself, you'll need to recursively checkout every submodule. -## Requirements +### Requirements - CMake - Perl @@ -38,10 +34,10 @@ If you want to build `thirdparty` for yourself, you'll need to recursively check - `clang` or `MSVC` as a compiler - On Linux setting cc and c++ to clang might be needed (using `update-alternatives`) -## Optional (but recommended) +### Optional (but recommended) - Ninja -### Android +#### Android - NDK, preferably version 27b - Remember to set the environment variable `ANDROID_NDK_HOME` to point to the install path (.bash_profile/.bashrc/.zprofile etc.) @@ -53,7 +49,7 @@ If you want to build `thirdparty` for yourself, you'll need to recursively check Note: we do not test cross-compiling for Android using Windows. -### iOS +#### iOS - Rust iOS target and toolchain @@ -63,7 +59,7 @@ rustup component add rust-src --toolchain nightly-aarch64-apple-darwin rustup target add aarch64-apple-ios ``` -## CMake +### CMake In the `build` directory, there'll be a folder for every supported platform, and inside each there will be a `CMakeLists.txt` file. To build, you must configure CMake using this platform-specific subdirectory and build from there. @@ -77,7 +73,7 @@ cmake .. -CMAKE_BUILD_TYPE=Debug cmake --build Debug --config Debug -j ``` -## Ninja (recommended) +### Ninja (recommended) Ninja is able to use parallel builds far better than CMake and picks up on # processors automatically. ```bash From 5b0eab6f71530e089e7cd7ff842aaad3aa70d5a2 Mon Sep 17 00:00:00 2001 From: Eduardo Menges Mattje Date: Fri, 28 Aug 2026 18:22:39 -0300 Subject: [PATCH 32/62] Simplified action to follow SuperGenius' style --- .github/workflows/build-targets.yml | 144 +++++++++++++--------------- .github/workflows/build.yml | 72 ++++---------- 2 files changed, 86 insertions(+), 130 deletions(-) diff --git a/.github/workflows/build-targets.yml b/.github/workflows/build-targets.yml index a99e3dd0..0bfd9a6b 100644 --- a/.github/workflows/build-targets.yml +++ b/.github/workflows/build-targets.yml @@ -2,85 +2,74 @@ name: Multiplatform build and upload on: pull_request: + paths-ignore: + - ".github/**" + - "README.md" workflow_dispatch: inputs: tag: description: "Release tag" - required: false type: string - build_android_arm64v8a_release: - description: 'Build Android arm64-v8a Release' - required: true + # Input names follow the SuperGenius convention build_-_; + # the prepare job maps them to uppercased env vars for the matrix filter. + build_Android-arm64-v8a_Release: + description: "Build Android arm64-v8a Release" default: true type: boolean - build_android_arm64v8a_debug: - description: 'Build Android arm64-v8a Debug' - required: true + build_Android-arm64-v8a_Debug: + description: "Build Android arm64-v8a Debug" default: true type: boolean - build_android_armv7a_release: - description: 'Build Android armeabi-v7a Release' - required: true + build_Android-armeabi-v7a_Release: + description: "Build Android armeabi-v7a Release" default: true type: boolean - build_android_armv7a_debug: - description: 'Build Android armeabi-v7a Debug' - required: true + build_Android-armeabi-v7a_Debug: + description: "Build Android armeabi-v7a Debug" default: true type: boolean - build_ios_release: - description: 'Build iOS Release' - required: true + build_iOS_Release: + description: "Build iOS Release" default: true type: boolean - build_ios_debug: - description: 'Build iOS Debug' - required: true + build_iOS_Debug: + description: "Build iOS Debug" default: true type: boolean - build_osx_release: - description: 'Build OSX Release' - required: true + build_OSX_Release: + description: "Build OSX Release" default: true type: boolean - build_osx_debug: - description: 'Build OSX Debug' - required: true + build_OSX_Debug: + description: "Build OSX Debug" default: true type: boolean - build_linux_x86_64_release: - description: 'Build Linux x86_64 Release' - required: true + build_Linux-x86_64_Release: + description: "Build Linux x86_64 Release" default: true type: boolean - build_linux_x86_64_debug: - description: 'Build Linux x86_64 Debug' - required: true + build_Linux-x86_64_Debug: + description: "Build Linux x86_64 Debug" default: true type: boolean - build_linux_aarch64_release: - description: 'Build Linux aarch64 Release' - required: true + build_Linux-aarch64_Release: + description: "Build Linux aarch64 Release" default: true type: boolean - build_linux_aarch64_debug: - description: 'Build Linux aarch64 Debug' - required: true + build_Linux-aarch64_Debug: + description: "Build Linux aarch64 Debug" default: true type: boolean - build_windows_release: - description: 'Build Windows Release' - required: true + build_Windows_Release: + description: "Build Windows Release" default: true type: boolean - build_windows_debug: - description: 'Build Windows Debug' - required: true + build_Windows_Debug: + description: "Build Windows Debug" default: true type: boolean sgns_enable_release_symbols: - description: 'Enable SGNS release symbols in CMake configure' - required: true + description: "Enable SGNS release symbols in CMake configure" default: false type: boolean @@ -99,41 +88,43 @@ jobs: id: gen env: GATED: ${{ github.event_name == 'workflow_dispatch' }} - BUILD_ANDROID_ARM64V8A_RELEASE: ${{ inputs.build_android_arm64v8a_release }} - BUILD_ANDROID_ARM64V8A_DEBUG: ${{ inputs.build_android_arm64v8a_debug }} - BUILD_ANDROID_ARMV7A_RELEASE: ${{ inputs.build_android_armv7a_release }} - BUILD_ANDROID_ARMV7A_DEBUG: ${{ inputs.build_android_armv7a_debug }} - BUILD_IOS_RELEASE: ${{ inputs.build_ios_release }} - BUILD_IOS_DEBUG: ${{ inputs.build_ios_debug }} - BUILD_OSX_RELEASE: ${{ inputs.build_osx_release }} - BUILD_OSX_DEBUG: ${{ inputs.build_osx_debug }} - BUILD_LINUX_X86_64_RELEASE: ${{ inputs.build_linux_x86_64_release }} - BUILD_LINUX_X86_64_DEBUG: ${{ inputs.build_linux_x86_64_debug }} - BUILD_LINUX_AARCH64_RELEASE: ${{ inputs.build_linux_aarch64_release }} - BUILD_LINUX_AARCH64_DEBUG: ${{ inputs.build_linux_aarch64_debug }} - BUILD_WINDOWS_RELEASE: ${{ inputs.build_windows_release }} - BUILD_WINDOWS_DEBUG: ${{ inputs.build_windows_debug }} + BUILD_ANDROID_ARM64_V8A_RELEASE: ${{ inputs.build_Android-arm64-v8a_Release }} + BUILD_ANDROID_ARM64_V8A_DEBUG: ${{ inputs.build_Android-arm64-v8a_Debug }} + BUILD_ANDROID_ARMEABI_V7A_RELEASE: ${{ inputs.build_Android-armeabi-v7a_Release }} + BUILD_ANDROID_ARMEABI_V7A_DEBUG: ${{ inputs.build_Android-armeabi-v7a_Debug }} + BUILD_IOS_RELEASE: ${{ inputs.build_iOS_Release }} + BUILD_IOS_DEBUG: ${{ inputs.build_iOS_Debug }} + BUILD_OSX_RELEASE: ${{ inputs.build_OSX_Release }} + BUILD_OSX_DEBUG: ${{ inputs.build_OSX_Debug }} + BUILD_LINUX_X86_64_RELEASE: ${{ inputs.build_Linux-x86_64_Release }} + BUILD_LINUX_X86_64_DEBUG: ${{ inputs.build_Linux-x86_64_Debug }} + BUILD_LINUX_AARCH64_RELEASE: ${{ inputs.build_Linux-aarch64_Release }} + BUILD_LINUX_AARCH64_DEBUG: ${{ inputs.build_Linux-aarch64_Debug }} + BUILD_WINDOWS_RELEASE: ${{ inputs.build_Windows_Release }} + BUILD_WINDOWS_DEBUG: ${{ inputs.build_Windows_Debug }} run: | set -euo pipefail # One entry per supported target/ABI/build-type combination. - # `toggle` names the workflow_dispatch input that enables the entry; - # it is stripped before the matrix is handed to the build workflow. + # `id` is the platform-ABI identifier used for artifact and tag names; + # `toggle` is the workflow_dispatch input enabling the entry, in its + # uppercased env-var form. It is stripped before the matrix is handed + # to the build workflow. MATRIX='[ - {"target":"Android","build-type":"Release","abi":"arm64-v8a","runner_key":"linux_x64","toggle":"BUILD_ANDROID_ARM64V8A_RELEASE"}, - {"target":"Android","build-type":"Debug","abi":"arm64-v8a","runner_key":"linux_x64","toggle":"BUILD_ANDROID_ARM64V8A_DEBUG"}, - {"target":"Android","build-type":"Release","abi":"armeabi-v7a","runner_key":"linux_x64","toggle":"BUILD_ANDROID_ARMV7A_RELEASE"}, - {"target":"Android","build-type":"Debug","abi":"armeabi-v7a","runner_key":"linux_x64","toggle":"BUILD_ANDROID_ARMV7A_DEBUG"}, - {"target":"iOS","build-type":"Release","abi":"","runner_key":"mac","toggle":"BUILD_IOS_RELEASE"}, - {"target":"iOS","build-type":"Debug","abi":"","runner_key":"mac","toggle":"BUILD_IOS_DEBUG"}, - {"target":"OSX","build-type":"Release","abi":"","runner_key":"mac","toggle":"BUILD_OSX_RELEASE"}, - {"target":"OSX","build-type":"Debug","abi":"","runner_key":"mac","toggle":"BUILD_OSX_DEBUG"}, - {"target":"Linux","build-type":"Release","abi":"x86_64","runner_key":"linux_x64","toggle":"BUILD_LINUX_X86_64_RELEASE","container":"ghcr.io/geniusventures/debian-bullseye:latest"}, - {"target":"Linux","build-type":"Debug","abi":"x86_64","runner_key":"linux_x64","toggle":"BUILD_LINUX_X86_64_DEBUG","container":"ghcr.io/geniusventures/debian-bullseye:latest"}, - {"target":"Linux","build-type":"Release","abi":"aarch64","runner_key":"linux_arm","toggle":"BUILD_LINUX_AARCH64_RELEASE","container":"ghcr.io/geniusventures/debian-bullseye:latest"}, - {"target":"Linux","build-type":"Debug","abi":"aarch64","runner_key":"linux_arm","toggle":"BUILD_LINUX_AARCH64_DEBUG","container":"ghcr.io/geniusventures/debian-bullseye:latest"}, - {"target":"Windows","build-type":"Release","abi":"","runner_key":"windows","toggle":"BUILD_WINDOWS_RELEASE"}, - {"target":"Windows","build-type":"Debug","abi":"","runner_key":"windows","toggle":"BUILD_WINDOWS_DEBUG"} + {"target":"Android","id":"Android-arm64-v8a","build-type":"Release","abi":"arm64-v8a","runner_key":"linux_x64","toggle":"BUILD_ANDROID_ARM64_V8A_RELEASE"}, + {"target":"Android","id":"Android-arm64-v8a","build-type":"Debug","abi":"arm64-v8a","runner_key":"linux_x64","toggle":"BUILD_ANDROID_ARM64_V8A_DEBUG"}, + {"target":"Android","id":"Android-armeabi-v7a","build-type":"Release","abi":"armeabi-v7a","runner_key":"linux_x64","toggle":"BUILD_ANDROID_ARMEABI_V7A_RELEASE"}, + {"target":"Android","id":"Android-armeabi-v7a","build-type":"Debug","abi":"armeabi-v7a","runner_key":"linux_x64","toggle":"BUILD_ANDROID_ARMEABI_V7A_DEBUG"}, + {"target":"iOS","id":"iOS","build-type":"Release","abi":"","runner_key":"mac","toggle":"BUILD_IOS_RELEASE"}, + {"target":"iOS","id":"iOS","build-type":"Debug","abi":"","runner_key":"mac","toggle":"BUILD_IOS_DEBUG"}, + {"target":"OSX","id":"OSX","build-type":"Release","abi":"","runner_key":"mac","toggle":"BUILD_OSX_RELEASE"}, + {"target":"OSX","id":"OSX","build-type":"Debug","abi":"","runner_key":"mac","toggle":"BUILD_OSX_DEBUG"}, + {"target":"Linux","id":"Linux-x86_64","build-type":"Release","abi":"x86_64","runner_key":"linux_x64","toggle":"BUILD_LINUX_X86_64_RELEASE","container":"ghcr.io/geniusventures/debian-bullseye:latest"}, + {"target":"Linux","id":"Linux-x86_64","build-type":"Debug","abi":"x86_64","runner_key":"linux_x64","toggle":"BUILD_LINUX_X86_64_DEBUG","container":"ghcr.io/geniusventures/debian-bullseye:latest"}, + {"target":"Linux","id":"Linux-aarch64","build-type":"Release","abi":"aarch64","runner_key":"linux_arm","toggle":"BUILD_LINUX_AARCH64_RELEASE","container":"ghcr.io/geniusventures/debian-bullseye:latest"}, + {"target":"Linux","id":"Linux-aarch64","build-type":"Debug","abi":"aarch64","runner_key":"linux_arm","toggle":"BUILD_LINUX_AARCH64_DEBUG","container":"ghcr.io/geniusventures/debian-bullseye:latest"}, + {"target":"Windows","id":"Windows","build-type":"Release","abi":"","runner_key":"windows","toggle":"BUILD_WINDOWS_RELEASE"}, + {"target":"Windows","id":"Windows","build-type":"Debug","abi":"","runner_key":"windows","toggle":"BUILD_WINDOWS_DEBUG"} ]' # On workflow_dispatch, drop the combinations whose toggle was unchecked. @@ -146,7 +137,7 @@ jobs: COUNT=$(jq '.include | length' <<<"$MATRIX") echo "Building $COUNT combinations:" - jq -r '.include[] | "- \(.target) \(.abi) \(.["build-type"])"' <<<"$MATRIX" + jq -r '.include[] | "- \(.id) \(.["build-type"])"' <<<"$MATRIX" if [ "$COUNT" -eq 0 ]; then echo "No target combinations enabled; nothing to build." >&2 @@ -159,6 +150,7 @@ jobs: name: Build and upload needs: prepare permissions: + # Allow the called workflow to create and push release tags. contents: write packages: read uses: ./.github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5d42a378..328d7ef0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -145,6 +145,11 @@ jobs: permissions: contents: write packages: read + env: + BUILD_DIRECTORY: build/${{ matrix.target }}/${{ matrix.build-type }}${{ matrix.abi && format('/{0}', matrix.abi) || '' }} + FILE_NAME: ${{ matrix.id }}-${{ matrix.build-type }}.tar.gz + IS_TAG_RELEASE: ${{ inputs.release-tag != '' }} + RELEASE_TAG: ${{ inputs.release-tag || format('{0}-{1}-{2}', matrix.id, github.ref_name, matrix.build-type) }} runs-on: ${{ fromJson(needs.resolve-runners.outputs[matrix.runner_key]) }} container: image: ${{matrix.container}} @@ -155,23 +160,17 @@ jobs: fail-fast: false matrix: ${{ fromJson(needs.resolve-runners.outputs.matrix) }} steps: - - name: Configure Git Bash on Windows + - name: Configure bash on Windows (use Git Bash, not WSL) if: ${{ runner.environment == 'self-hosted' && matrix.target == 'Windows' }} run: | - $gitBinPath = "C:\Program Files\Git\bin" - - if (Test-Path $gitBinPath) { - Add-Content -Path $env:GITHUB_PATH -Value $gitBinPath - $env:PATH = "$gitBinPath;$env:PATH" - } - - Write-Output "Git Bash configured for bash shell commands" - $bashLocation = (Get-Command bash.exe -ErrorAction SilentlyContinue).Source - if ($bashLocation) { - Write-Output "Bash location: $bashLocation" - } else { - Write-Output "WARNING: bash.exe not found in PATH" + foreach ($p in @("C:\Program Files\Git\bin", "C:\Program Files\Git\usr\bin")) { + if (Test-Path $p) { + Add-Content -Path $env:GITHUB_PATH -Value $p + $env:PATH = "$p;$env:PATH" + } } + $bash = (Get-Command bash.exe -ErrorAction SilentlyContinue).Source + Write-Output $(if ($bash) { "Bash location: $bash" } else { "WARNING: bash.exe not found in PATH" }) - name: Clean workspace (self-hosted runners) if: ${{ runner.environment == 'self-hosted' }} @@ -206,10 +205,11 @@ jobs: shell: bash - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: # Keep submodule checkout explicit so we can control retries and fetch behavior. submodules: false + persist-credentials: true # Needed to push release tags later - name: Harden Git network settings shell: bash @@ -315,16 +315,6 @@ jobs: - name: Add wasm Rust target run: rustup target add wasm32-unknown-emscripten - - name: Set build directory - run: | - if [ '${{matrix.abi}}' ]; then - BUILD_DIRECTORY=build/${{matrix.target}}/${{matrix.build-type}}/${{matrix.abi}} - else - BUILD_DIRECTORY=build/${{matrix.target}}/${{matrix.build-type}} - fi - echo "BUILD_DIRECTORY=$BUILD_DIRECTORY" >> $GITHUB_ENV - shell: bash - - name: Configure CMake for Mac if: ${{ matrix.target == 'OSX'}} run: cmake -S build/${{matrix.target}} -B $BUILD_DIRECTORY -DCMAKE_BUILD_TYPE=${{matrix.build-type}} -DPLATFORM=MAC_UNIVERSAL -DSGNS_ENABLE_RELEASE_SYMBOLS=${{ env.SGNS_ENABLE_RELEASE_SYMBOLS }} @@ -353,34 +343,7 @@ jobs: if: ${{ inputs.upload }} working-directory: ${{env.BUILD_DIRECTORY}} shell: bash - run: | - if [ '${{matrix.abi}}' ]; then - FILE_NAME="${{matrix.target}}-${{matrix.abi}}-${{matrix.build-type}}.tar.gz" - else - FILE_NAME="${{matrix.target}}-${{matrix.build-type}}.tar.gz" - fi - - echo "FILE_NAME=$FILE_NAME" >> $GITHUB_ENV - - tar --no-wildcards-match-slash --exclude='./*/src' --exclude='./*/tmp' --transform='s|^\.|${{env.BUILD_DIRECTORY}}|g' -czf $FILE_NAME ./*/ - - - name: Set release tag - shell: bash - run: | - if [ -n '${{ inputs.release-tag }}' ]; then - RELEASE_TAG="${{ inputs.release-tag }}" - IS_TAG_RELEASE="true" - else - if [ '${{matrix.abi}}' ]; then - RELEASE_TAG="${{ matrix.target }}-${{matrix.abi}}-${{ github.ref_name }}-${{ matrix.build-type }}" - else - RELEASE_TAG="${{ matrix.target }}-${{ github.ref_name }}-${{ matrix.build-type }}" - fi - IS_TAG_RELEASE="false" - fi - - echo "RELEASE_TAG=$RELEASE_TAG" >> $GITHUB_ENV - echo "IS_TAG_RELEASE=$IS_TAG_RELEASE" >> $GITHUB_ENV + run: tar --no-wildcards-match-slash --exclude='./*/src' --exclude='./*/tmp' --transform='s|^\.|${{env.BUILD_DIRECTORY}}|g' -czf "$FILE_NAME" ./*/ - name: Create release tag if: ${{ inputs.upload }} @@ -434,4 +397,5 @@ jobs: - name: Upload file if: ${{ inputs.upload }} working-directory: ${{env.BUILD_DIRECTORY}} - run: gh release upload ${{env.RELEASE_TAG}} ${{env.FILE_NAME}} --clobber + shell: bash + run: gh release upload "$RELEASE_TAG" "$FILE_NAME" --clobber From cc3bbc4b9dfde841df0dadb28a0549229f2b22a0 Mon Sep 17 00:00:00 2001 From: itsafuu Date: Fri, 28 Aug 2026 18:20:53 -0400 Subject: [PATCH 33/62] Update asiomgr with dht set, bitswap error handling --- AsyncIOManager | 2 +- ipfs-bitswap-cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/AsyncIOManager b/AsyncIOManager index 2aea7454..36e0dd1b 160000 --- a/AsyncIOManager +++ b/AsyncIOManager @@ -1 +1 @@ -Subproject commit 2aea74540f265dc75333b43a4928c4b93ea5553e +Subproject commit 36e0dd1b1f44d1480332107ebcd42bb48a8af926 diff --git a/ipfs-bitswap-cpp b/ipfs-bitswap-cpp index d308c1f6..73092a88 160000 --- a/ipfs-bitswap-cpp +++ b/ipfs-bitswap-cpp @@ -1 +1 @@ -Subproject commit d308c1f6457356b1b926c040ff8de6083409bd8f +Subproject commit 73092a880514da338fe16c942f4dcca3fdce55e1 From 0aeef6156e2717c6255511bc82d306303f48e386 Mon Sep 17 00:00:00 2001 From: Super Genius Date: Sat, 28 Mar 2026 18:12:49 -0700 Subject: [PATCH 34/62] Checkpoint: MNN Vulkan attention updates and OSX MNN build wiring --- build/CommonCompilerOptions.cmake | 2 -- build/CommonTargets.cmake | 8 ++++++++ build/OSX/CMakeLists.txt | 25 +++++++++++++++++++++++-- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/build/CommonCompilerOptions.cmake b/build/CommonCompilerOptions.cmake index 04552786..38ee40fb 100644 --- a/build/CommonCompilerOptions.cmake +++ b/build/CommonCompilerOptions.cmake @@ -143,5 +143,3 @@ option(MNN_SUPPORT_TRANSFORMER_FUSE "Enable MNN transformer fuse ops for OSX ext if (MNN_BUILD_TESTS) set(MNN_TEST_BYPRODUCT "${CMAKE_CURRENT_BINARY_DIR}/MNN/lib/run_test.out") endif() - - diff --git a/build/CommonTargets.cmake b/build/CommonTargets.cmake index 9374aa11..808f3e75 100644 --- a/build/CommonTargets.cmake +++ b/build/CommonTargets.cmake @@ -399,13 +399,21 @@ if(NOT APPLE OR (APPLE AND CMAKE_OSX_SYSROOT MATCHES "iPhoneOS")) -DCMAKE_INSTALL_PREFIX:PATH= -DMNN_BUILD_SHARED_LIBS:BOOL=OFF -DMNN_BUILD_TEST:BOOL=${MNN_BUILD_TESTS} + -DMNN_BUILD_LLM:BOOL=ON + -DMNN_BUILD_LLM_OMNI:BOOL=ON + -DMNN_LOW_MEMORY:BOOL=ON -DMNN_BUILD_TOOLS:BOOL=OFF -DMNN_BUILD_PROTOBUFFER:BOOL=OFF -DMNN_VULKAN:BOOL=ON + -DMNN_VULKAN_IMAGE:BOOL=OFF + -DMNN_SUPPORT_TRANSFORMER_FUSE:BOOL=${MNN_SUPPORT_TRANSFORMER_FUSE} -DMNN_WIN_RUNTIME_MT:BOOL=ON ${_CMAKE_COMMON_CACHE_ARGS} ${_MNN_EXTRA_PARAM} DEPENDS ${_MNN_DEPENDS} ${vulkanTarget} + BYPRODUCTS + "${CMAKE_CURRENT_BINARY_DIR}/MNN/lib/${CMAKE_STATIC_LIBRARY_PREFIX}MNN${CMAKE_STATIC_LIBRARY_SUFFIX}" + ${MNN_TEST_BYPRODUCT} ) set(_FINDPACKAGE_MNN_CONFIG_DIR "${CMAKE_CURRENT_BINARY_DIR}/MNN/lib/cmake/MNN") diff --git a/build/OSX/CMakeLists.txt b/build/OSX/CMakeLists.txt index ca828f18..586a5fb8 100644 --- a/build/OSX/CMakeLists.txt +++ b/build/OSX/CMakeLists.txt @@ -167,6 +167,11 @@ set(_ZKLLVM_EXTRA_PARAM -DLLVM_INCLUDE_UTILS:BOOL=OFF -DLLVM_INCLUDE_TESTS:BOOL=OFF ) + +if (MNN_BUILD_TESTS) + set (MNN_X86_TEST_BYPRODUCT "${CMAKE_CURRENT_BINARY_DIR}/MNN/src/MNN_X86-build/run_test.out") +endif() + # MNN Has separate source files for x86 and ARM, so I think we need to build twice and lipo combine ExternalProject_Add(MNN_X86 PREFIX MNN @@ -183,15 +188,24 @@ ExternalProject_Add(MNN_X86 -DENABLE_STRICT_TRY_COMPILE:BOOL=${ENABLE_STRICT_TRY_COMPILE} -DMNN_BUILD_SHARED_LIBS:BOOL=OFF -DMNN_BUILD_TEST:BOOL=${MNN_BUILD_TESTS} + -DMNN_BUILD_LLM:BOOL=ON + -DMNN_BUILD_LLM_OMNI:BOOL=ON + -DMNN_LOW_MEMORY:BOOL=ON + -DMNN_SUPPORT_TRANSFORMER_FUSE:BOOL=${MNN_SUPPORT_TRANSFORMER_FUSE} -DMNN_BUILD_TOOLS:BOOL=OFF -DMNN_BUILD_PROTOBUFFER:BOOL=OFF -DMNN_VULKAN:BOOL=ON + -DMNN_VULKAN_IMAGE:BOOL=OFF -DMNN_WIN_RUNTIME_MT:BOOL=ON ${_MNN_EXTRA_PARAM} DEPENDS ${_MNN_DEPENDS} BUILD_BYPRODUCTS - "${CMAKE_CURRENT_BINARY_DIR}/MNN/x86_64/lib/libMNN.a" + "${CMAKE_CURRENT_BINARY_DIR}/MNN/x86_64/lib/libMNN.a" + ${MNN_X86_TEST_BYPRODUCT} ) +if (MNN_BUILD_TESTS) + set (MNN_ARM_TEST_BYPRODUCT "${CMAKE_CURRENT_BINARY_DIR}/MNN/src/MNN_ARM-build/run_test.out") +endif() ExternalProject_Add(MNN_ARM PREFIX MNN @@ -208,14 +222,20 @@ ExternalProject_Add(MNN_ARM -DENABLE_STRICT_TRY_COMPILE:BOOL=${ENABLE_STRICT_TRY_COMPILE} -DMNN_BUILD_SHARED_LIBS:BOOL=OFF -DMNN_BUILD_TEST:BOOL=${MNN_BUILD_TESTS} + -DMNN_BUILD_LLM:BOOL=ON + -DMNN_BUILD_LLM_OMNI:BOOL=ON + -DMNN_LOW_MEMORY:BOOL=ON + -DMNN_SUPPORT_TRANSFORMER_FUSE:BOOL=${MNN_SUPPORT_TRANSFORMER_FUSE} -DMNN_BUILD_TOOLS:BOOL=OFF -DMNN_BUILD_PROTOBUFFER:BOOL=OFF -DMNN_VULKAN:BOOL=ON + -DMNN_VULKAN_IMAGE:BOOL=OFF -DMNN_WIN_RUNTIME_MT:BOOL=ON ${_MNN_EXTRA_PARAM} DEPENDS ${_MNN_DEPENDS} BUILD_BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/MNN/arm64/lib/libMNN.a" + ${MNN_ARM_TEST_BYPRODUCT} ) set(MNN_X86_LIB "${CMAKE_CURRENT_BINARY_DIR}/MNN/x86_64/lib/libMNN.a") @@ -238,7 +258,8 @@ add_custom_command( # Add target for fat library add_custom_target(MNN_Fat ALL - DEPENDS ${MNN_FAT_LIB}) + DEPENDS ${MNN_FAT_LIB} +) # Ensure the destination directory exists file(MAKE_DIRECTORY ${MNN_FAT_CMAKE_DIR}) From 11162deac85940e1d4e557e92e0b15ad476e3aca Mon Sep 17 00:00:00 2001 From: Super Genius Date: Tue, 31 Mar 2026 14:50:12 -0700 Subject: [PATCH 35/62] Document TurboQuant K Phase 2 completion --- AGENTS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AGENTS.md b/AGENTS.md index 810ae558..f0908ba3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -45,5 +45,6 @@ ninja ## Practical editing guidance for agents - Make minimal, surgical changes in the relevant platform file and/or `build/CommonTargets.CMake`; avoid broad refactors across vendored sources. +- Minimal changes do not justify magic numbers; when adding or touching non-obvious literals, use short named constants or helpers so the code remains human-readable. - When adding a dependency, update both `DEPENDS` and required `*_DIR`/include cache args for downstream consumers. - Validate changes by mirroring one CI configure/build path for the affected platform. From 11994aa79f53b4dc1be7a31bae558be94ae993b4 Mon Sep 17 00:00:00 2001 From: Super Genius Date: Sat, 29 Aug 2026 12:24:17 -0700 Subject: [PATCH 36/62] Update asiomgr with StartFindingPeersWithRetry use-after-free fix --- AsyncIOManager | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AsyncIOManager b/AsyncIOManager index 36e0dd1b..6f4f5ce4 160000 --- a/AsyncIOManager +++ b/AsyncIOManager @@ -1 +1 @@ -Subproject commit 36e0dd1b1f44d1480332107ebcd42bb48a8af926 +Subproject commit 6f4f5ce4c0aa2c5a260862edb384563ab98edb6a From 86c2467a709a3ae717dd29e062bb6e35a1324cc6 Mon Sep 17 00:00:00 2001 From: Super Genius Date: Sat, 29 Aug 2026 12:24:31 -0700 Subject: [PATCH 37/62] docs(quick-260829-gj4): Fix use-after-free in IPFSDevice::StartFindingPeersWithRetry (AsyncIOManager) --- .planning/STATE.md | 12 + .../260829-gj4-PLAN.md | 328 ++++++++++++++++++ .../260829-gj4-SUMMARY.md | 104 ++++++ 3 files changed, 444 insertions(+) create mode 100644 .planning/STATE.md create mode 100644 .planning/quick/260829-gj4-fix-use-after-free-in-ipfsdevice-startfi/260829-gj4-PLAN.md create mode 100644 .planning/quick/260829-gj4-fix-use-after-free-in-ipfsdevice-startfi/260829-gj4-SUMMARY.md diff --git a/.planning/STATE.md b/.planning/STATE.md new file mode 100644 index 00000000..24cc3b6f --- /dev/null +++ b/.planning/STATE.md @@ -0,0 +1,12 @@ +# Project State — thirdparty + +> Submodule collection repo (no ROADMAP.md by design — see SUBREPOS.md for the submodule map). +> Quick tasks are tracked in this file; planning artifacts live in `.planning/quick/`. + +## Quick Tasks Completed + +| # | Description | Date | Commit | Directory | +|---|-------------|------|--------|-----------| +| 260829-gj4 | Fix use-after-free in IPFSDevice::StartFindingPeersWithRetry (AsyncIOManager): capture shared_from_this in dhtretry_ timer handler; regression test ipfs_device_test | 2026-08-29 | AsyncIOManager@6f4f5ce (dev_ipfsdevice_retry_uaf) | [260829-gj4-fix-use-after-free-in-ipfsdevice-startfi](./quick/260829-gj4-fix-use-after-free-in-ipfsdevice-startfi/) | + +Last activity: 2026-08-29 - Completed quick task 260829-gj4: Fix use-after-free in IPFSDevice::StartFindingPeersWithRetry (AsyncIOManager) diff --git a/.planning/quick/260829-gj4-fix-use-after-free-in-ipfsdevice-startfi/260829-gj4-PLAN.md b/.planning/quick/260829-gj4-fix-use-after-free-in-ipfsdevice-startfi/260829-gj4-PLAN.md new file mode 100644 index 00000000..c40a2edf --- /dev/null +++ b/.planning/quick/260829-gj4-fix-use-after-free-in-ipfsdevice-startfi/260829-gj4-PLAN.md @@ -0,0 +1,328 @@ +--- +phase: quick-260829-gj4 +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: + - AsyncIOManager/src/IPFSCommon.cpp + - AsyncIOManager/test/src/ipfs_device_test.cpp + - AsyncIOManager/test/src/CMakeLists.txt +autonomous: true +requirements: [GJ4-UAF-01] + +must_haves: + truths: + - "An armed dhtretry_ timer keeps its IPFSDevice alive until the handler completes (no use-after-free)" + - "The dead local deadline_timer in StartFindingPeersWithRetry is removed" + - "A regression test proves the device outlives the armed 10s timer after the last external shared_ptr is dropped" + - "An end-to-end test proves the full retry chain completes on a valid object after the external reference is dropped" + - "The canonical library build (build/OSX/Debug) succeeds and existing tests still pass" + artifacts: + - path: "AsyncIOManager/src/IPFSCommon.cpp" + provides: "shared_from_this-captured timer handler" + contains: "self->StartFindingPeers" + - path: "AsyncIOManager/test/src/ipfs_device_test.cpp" + provides: "UAF regression + retry survival tests" + min_lines: 80 + - path: "AsyncIOManager/test/src/CMakeLists.txt" + provides: "ipfs_device_test target in network-tests gate" + contains: "addtest(ipfs_device_test" + key_links: + - from: "AsyncIOManager/src/IPFSCommon.cpp (StartFindingPeersWithRetry lambda)" + to: "std::enable_shared_from_this (include/IPFSCommon.hpp:52)" + via: "auto self = shared_from_this(); captured by value in async_wait lambda" + pattern: "self = shared_from_this" + - from: "AsyncIOManager/test/src/ipfs_device_test.cpp" + to: "IPFSDevice::createWithBitswap (include/IPFSCommon.hpp:84)" + via: "createWithBitswap(runner.ioc(), clientBitswap, nullptr).value()" + pattern: "createWithBitswap" + - from: "AsyncIOManager/test/src/CMakeLists.txt" + to: "AsyncIOManager library" + via: "target_link_libraries(ipfs_device_test ... AsyncIOManager ...)" + pattern: "ipfs_device_test" +--- + + +Fix a use-after-free in `IPFSDevice::StartFindingPeersWithRetry` (AsyncIOManager submodule): the 10-second `dhtretry_` timer lambda captures raw `this`, so when the IPFSDevice is destroyed while the timer is armed (e.g., the process-global FileManager singleton is `setBitswap`'d to the next node), the handler runs on freed memory. Crash reports fault in `spdlog::logger::should_log`. + +Purpose: eliminate a recurring crash in IPFS node teardown/reinit. +Output: 4-line surgical fix in `src/IPFSCommon.cpp`, a new gated regression test, passing builds in two build dirs, one commit inside the AsyncIOManager submodule on a new branch off `36e0dd1`. + + + +@$HOME/.claude/get-shit-done/workflows/execute-plan.md + + + +All paths are relative to the project root: `/Users/Shared/SSDevelopment/Development/GeniusVentures/GeniusNetwork/thirdparty` + +Read these exact ranges before editing (one pass each, no re-reads): + +- `AsyncIOManager/src/IPFSCommon.cpp` lines 100-215 — the buggy function (154-179) AND the existing correct pattern in `RequestBlockMain` (192-196) that this fix must mirror. +- `AsyncIOManager/include/IPFSCommon.hpp` lines 30-230 — class declaration: `enable_shared_from_this` at line 52, `createWithBitswap` factory at 84-87, public `StartFindingPeersWithRetry` at 124-130, `m_logger` at 198, `bitswap_` at 205, `dhtretry_` member at 206. +- `AsyncIOManager/test/src/ipfs_loader_test.cpp` lines 1-142 — fixture house pattern (`IPFSIntegrationTest`, `BitswapNode`, `IOContextRunner`, `pollUntil`). +- `AsyncIOManager/test/testutil/bitswap_node.hpp` (whole file) and `AsyncIOManager/test/testutil/asio_helpers.hpp` (whole file). +- `AsyncIOManager/test/src/CMakeLists.txt` (whole file) — `ipfs_loader_test` block at 113-139 is the template to copy. + + + + +```cpp +void IPFSDevice::StartFindingPeersWithRetry( std::shared_ptr ioc, + const sgns::ipfs_bitswap::CID &cid, + std::string filename, + int addressoffset, + bool parse, + bool save, + CompletionCallback handle_read ) +{ + boost::asio::deadline_timer dhtretry( *ioc.get() ); // line 162: DEAD LOCAL — never used + boost::posix_time::time_duration timeout( boost::posix_time::milliseconds( 10000 ) ); + dhtretry_.expires_from_now( timeout ); + dhtretry_.async_wait( + [ioc, cid, filename, addressoffset, parse, save, handle_read, this]( const boost::system::error_code &ec ) + { + if ( !ec ) + { + // Timer expired, call StartFindingPeers again with captured parameters + this->StartFindingPeers( ioc, cid, filename, addressoffset, parse, save, handle_read ); + } + else + { + // Handle error + m_logger->error( "Error: {}", ec.message() ); + } + } ); +} +``` + + + +```cpp +// Capture shared_ptr to keep this object alive during callback +auto self = shared_from_this(); +bitswap_->RequestContent( + cid, + [self, ioc, filename, parse, save, handle_read]( ... ) { self->m_logger->error( ... ); ... } ); +``` + + + +```cpp +class IPFSDevice : public std::enable_shared_from_this // line 52 +{ +public: + using ResultType = outcome::result< + std::shared_ptr, std::vector>>>>; + using CompletionCallback = std::function< + void( std::shared_ptr ioc, ResultType buffers, bool parse, bool save )>; + + static outcome::result> createWithBitswap( + std::shared_ptr ioc, + std::shared_ptr bitswap, + std::shared_ptr dht = nullptr ); // lines 84-87 + + void StartFindingPeersWithRetry( std::shared_ptr ioc, + const sgns::ipfs_bitswap::CID &cid, std::string filename, + int addressoffset, bool parse, bool save, + CompletionCallback handle_read ); // lines 124-130, PUBLIC + +private: + sgns::asiomgr::Logger m_logger = sgns::asiomgr::createLogger( "IPFSCommon" ); // 198 + std::shared_ptr bitswap_; // 205 + boost::asio::deadline_timer dhtretry_; // 206 — member timer, default-constructed +}; +``` + + + +```cpp +class IOContextRunner { // owns io_context + work guard + background run() thread +public: + std::shared_ptr ioc() const; + // dtor stops context and joins thread +}; + +template // THE wait-condition template — never sleep_for in new test code +bool pollUntil( Predicate pred, std::chrono::milliseconds timeout = std::chrono::seconds( 30 ), + std::chrono::milliseconds interval = std::chrono::milliseconds( 50 ) ); + +class BitswapNode { // full libp2p host + noise + Bitswap on a background io thread +public: + std::shared_ptr getBitswap() const; + std::shared_ptr getIOContext() const; + libp2p::peer::PeerInfo getPeerInfo() const; +}; +``` + + + + +**Verified environment facts:** +- `AsyncIOManager/build/OSX/Debug` does NOT exist yet — fresh configure (mkdir first). `build/OSX/CMakeLists.txt` pins `CMAKE_OSX_ARCHITECTURES "x86_64"` (line 22, Rosetta on arm64) — this is the project's prescribed OSX config; follow it exactly. If configure/build fails on architecture or missing deps, STOP and report — do not improvise a different build config. +- Submodule git state: detached HEAD at `36e0dd1`, clean working tree. Local branch `develop` (`d9862aa`) has DIVERGED from `36e0dd1` — never switch to it. The fix goes on a NEW branch off `36e0dd1`. +- `addtest()` (cmake/functions.cmake) links `GTest::gtest_main` automatically and outputs binaries to `${CMAKE_BINARY_DIR}/test_bin/` — no custom main needed in the test file. +- Tests are double-gated: top-level `BUILD_TESTING` defaults OFF; IPFS tests additionally need `ASYNC_IO_MANAGER_NETWORK_TESTS=ON`. + +**Scope guard (user-specified):** Minimal change ONLY. Do NOT touch `StartFindingPeers`, the "Empty provider list received" path (pre-convergence DHT behavior the retry exists to ride out — not this bug), `RequestBlockMain`, or anything else in the file. + + + + + + Task 1: Capture shared_from_this in the dhtretry_ timer lambda + AsyncIOManager/src/IPFSCommon.cpp + + - Behavior: after `IPFSDevice::StartFindingPeersWithRetry` arms `dhtretry_`, destroying the last external `shared_ptr` does NOT destroy the device until the 10s handler has run and completed (the handler itself holds a strong reference). Formalized as the two regression tests in Task 2. + + +Surgical edit to `IPFSDevice::StartFindingPeersWithRetry` ONLY (src/IPFSCommon.cpp lines 154-179), mirroring the existing `RequestBlockMain` self-capture pattern at lines 192-196. Exactly four changes, nothing else in the file: + +1. DELETE line 162 — the dead local `boost::asio::deadline_timer dhtretry( *ioc.get() );` (constructed, never used; the member `dhtretry_` is what gets armed). +2. INSERT `auto self = shared_from_this();` on its own line immediately after the `dhtretry_.expires_from_now( timeout );` line (safe: the class inherits `std::enable_shared_from_this` at include/IPFSCommon.hpp:52 and both factories return `shared_ptr`). +3. In the `async_wait` lambda capture list, replace the trailing `this` capture with `self`: `[ioc, cid, filename, addressoffset, parse, save, handle_read, self]`. +4. Route BOTH branches through `self->`: the timeout branch becomes `self->StartFindingPeers( ioc, cid, filename, addressoffset, parse, save, handle_read );` and the error branch becomes `self->m_logger->error( "Error: {}", ec.message() );`. + +Do NOT add a destructor `dhtretry_.cancel()`. Rationale (recorded here per user decision): with the self-capture, the destructor cannot run while a handler is pending (the pending handler owns a strong reference), and destroying the `dhtretry_` member already cancels outstanding waits per Boost.Asio semantics — an explicit dtor cancel would be unreachable dead code. + +Keep the existing comment "Timer expired, call StartFindingPeers again with captured parameters" and add a one-line comment above `auto self = shared_from_this();` matching the house wording: "Capture shared_ptr to keep this object alive during callback". Preserve Allman bracing and the file's existing alignment/style. Leave the pre-existing `10000` ms literal untouched (production constant, out of scope). + + + cd /Users/Shared/SSDevelopment/Development/GeniusVentures/GeniusNetwork/thirdparty/AsyncIOManager && grep -c 'dhtretry( \*ioc' src/IPFSCommon.cpp | grep -x 0 && grep -n 'self = shared_from_this' src/IPFSCommon.cpp | wc -l | grep -x 2 && grep -n 'handle_read, this\]' src/IPFSCommon.cpp | wc -l | grep -x 0 && echo FIX-OK + + Dead local gone; two `shared_from_this()` captures in the file (RequestBlockMain's + the new one); no `this]` capture remains in StartFindingPeersWithRetry; both branches use `self->`; no other line of the file changed (verify with git diff — only the function body at 154-179 differs). + + + + Task 2: Add gated regression tests ipfs_device_test + AsyncIOManager/test/src/ipfs_device_test.cpp, AsyncIOManager/test/src/CMakeLists.txt + +Create `AsyncIOManager/test/src/ipfs_device_test.cpp` (new file), gated behind the network-tests flag like its siblings. Header comment at top: purpose is regression coverage for the use-after-free in `StartFindingPeersWithRetry`. + +Includes (house order): `gtest/gtest.h`, `IPFSCommon.hpp`, `testutil/asio_helpers.hpp`, `testutil/bitswap_node.hpp`, `libp2p/multi/content_identifier_codec.hpp`, then ``, ``. `using namespace sgns;`. + +Named constant (no magic numbers): `constexpr char kNeverPublishedCid[] = "QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG";` — a valid CIDv0 that always parses but is never fetched by the local node (no provider is ever registered for it). + +Fixture — modeled on `IPFSIntegrationTest` in ipfs_loader_test.cpp lines 26-72 but with ONE BitswapNode (client only) and NO FileManagerTestFixture base (plain `::testing::Test`; these tests never touch disk): + +class `IPFSDeviceRetryTest : public ::testing::Test` with: +- `static void SetUpTestSuite()` — wraps `s_clientNode = std::make_unique();` in try/catch that issues `GTEST_SKIP()` on exception (copy the reference pattern). No `sleep_for` — node construction is synchronous and addresses are populated when the ctor returns. +- `static void TearDownTestSuite()` — `s_clientNode.reset();` +- private `static std::unique_ptr s_clientNode;` plus out-of-class definition. + +TEST_F 1 — `IPFSDeviceRetryTest, RetryTimerKeepsDeviceAlive` (THE regression; instant assertion, then deterministic cleanup): +1. `IOContextRunner runner;` +2. `auto device = IPFSDevice::createWithBitswap( runner.ioc(), s_clientNode->getBitswap(), nullptr ).value();` +3. `const auto cid = libp2p::multi::ContentIdentifierCodec::fromString( kNeverPublishedCid ).value();` +4. `auto fired = std::make_shared( false );` — shared_ptr so the completion callback has no dangling by-ref capture. +5. No-op callback: `[fired]( std::shared_ptr, IPFSDevice::ResultType, bool, bool ) { *fired = true; }` (match `CompletionCallback`'s 4 params exactly; leave params unnamed where unused). +6. Arm: `device->StartFindingPeersWithRetry( runner.ioc(), cid, "uaf_probe.bin", 0, false, false, callback );` +7. `std::weak_ptr watch = device;` then `device.reset();` — drops the last EXTERNAL reference while the 10s timer is armed (the UAF window). +8. THE assertion: `EXPECT_NE( watch.lock(), nullptr )` with a message like "device was freed while retry timer was armed (use-after-free)". Pre-fix this FAILS (object destroyed instantly); post-fix the armed handler's `self` capture keeps it alive. +9. Deterministic cleanup + full-lifecycle assertion: `ASSERT_TRUE( pollUntil( [&watch]() { return watch.expired(); }, std::chrono::seconds( 20 ) ) )` with message "armed retry handler must release the device after the timer fires". This waits out the 10s timer so the test binary never tears down the suite BitswapNode with a live device/armed handler still pending (avoids teardown-order crashes when this test is run alone via --gtest_filter). + +TEST_F 2 — `IPFSDeviceRetryTest, RetryChainCompletesAfterReferenceDropped` (end-to-end, ~10-12s): +1.-6. Same setup as TEST_F 1 (fresh `IOContextRunner`, fresh device, same cid), but the callback records BOTH completion and error: `auto fired = std::make_shared( false ); auto gotFailure = std::make_shared( false );` — callback sets `*fired = true;` and, if `!result.has_value()`, sets `*gotFailure = true;` (the verified failure chain delivers `Error::CANNOT_DECODE`). +7. Arm FIRST, then `device.reset();` (drop the strong ref before the timer fires). +8. `ASSERT_TRUE( pollUntil( [fired]() { return *fired; }, std::chrono::seconds( 20 ) ) )` with message "retry chain must complete after the external reference is dropped". Verified chain this asserts: timer fires at +10s → `self->StartFindingPeers` → `dht_ == nullptr` → warn → `RequestBlockMain` → `bitswap_->RequestContent` → no providers → failure path posts `handle_read` (failure `CANNOT_DECODE`) onto `runner.ioc()` → background thread runs it → `*fired = true`. handle_read firing proves the ENTIRE retry chain executed on a valid object after the last external ref was dropped. +9. `EXPECT_TRUE( *gotFailure )` — completion was the expected failure, not a hang. +10. Teardown hygiene: `EXPECT_TRUE( pollUntil( [&watch]() { return watch.expired(); }, std::chrono::seconds( 5 ) ) );` + +All waits go through `pollUntil` (project wait-condition template). No `sleep_for` anywhere in the new file. Allman braces, always-braced ifs, initialized variables, Doxygen-style file header comment. + +CMakeLists edit — in `AsyncIOManager/test/src/CMakeLists.txt`, inside the existing `if(ASYNC_IO_MANAGER_NETWORK_TESTS)` block, add after the `ipfs_saver_test` block (lines 141-166) a new block that is a byte-for-byte copy of the `ipfs_loader_test` block with the name changed to `ipfs_device_test` and the source `ipfs_device_test.cpp` — identical `target_link_libraries` list (AsyncIOManager, asiomgr_testutil, ${Boost_LIBRARIES}, ipfs-bitswap-cpp, ipfs-bitswap-proto, ipfs-unixfs-proto, ipfs-lite-cpp::ipld_node, Boost::Boost.DI, the p2p::* targets, spdlog, soralog, yaml-cpp, Boost::boost, ${WIN_CRYPT_LIBRARY}). + + + cd /Users/Shared/SSDevelopment/Development/GeniusVentures/GeniusNetwork/thirdparty/AsyncIOManager && grep -v '^\s*//' test/src/ipfs_device_test.cpp | grep -c 'sleep_for' | grep -x 0 && grep -c 'addtest(ipfs_device_test' test/src/CMakeLists.txt | grep -x 1 && grep -c 'weak_ptr' test/src/ipfs_device_test.cpp | grep -x 2 && echo TESTS-OK + + New test file compiles-ready with two TEST_F cases using pollUntil only; CMake block added inside the network-tests gate with link libs identical to ipfs_loader_test. + + + + Task 3: Build both configs, run tests, commit inside the submodule + AsyncIOManager (no source edits — build dirs + git commit) + +STEP A — canonical library build (user's prescribed config, fresh dir; note the user's original command said "Ninjda" — corrected to Ninja): + +mkdir -p AsyncIOManager/build/OSX/Debug +cd AsyncIOManager/build/OSX/Debug && cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Debug && ninja AsyncIOManager && ninja install + +(`cmake ..` resolves to `build/OSX/CMakeLists.txt`, which pins x86_64 — expected on this arm64 machine via Rosetta.) If configure or build fails on architecture or missing dependencies, STOP and report the exact error — do NOT improvise an alternate build config, toolchain, or architecture. + +STEP B — test build in a SEPARATE dir so the canonical Debug dir is not repurposed: + +mkdir -p AsyncIOManager/build/OSX/DebugTests +cd AsyncIOManager/build/OSX/DebugTests && cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON -DASYNC_IO_MANAGER_NETWORK_TESTS=ON +ninja ipfs_device_test mnn_loader_test mnn_saver_test filemanager_test + +Run the new regression tests (binary lives at `test_bin/ipfs_device_test` per the `addtest()` RUNTIME_OUTPUT_DIRECTORY): + +cd AsyncIOManager/build/OSX/DebugTests && ./test_bin/ipfs_device_test + +Expected: `[ PASSED ] 2 tests`. If `RetryTimerKeepsDeviceAlive` fails with the "device was freed" message, the Task 1 fix is wrong or incomplete — go back to Task 1; do not touch the test. + +Run the always-on file-based tests for regressions (IPFSCommon.cpp is in the shared AsyncIOManager library): + +cd AsyncIOManager/build/OSX/DebugTests && ctest --output-on-failure -R "mnn_loader_test|mnn_saver_test|filemanager_test" + +STEP C — commit INSIDE the AsyncIOManager submodule only. Guard rails: verify `git -C AsyncIOManager rev-parse --short HEAD` prints `36e0dd1` and `git -C AsyncIOManager branch --show-current` is empty (detached) BEFORE branching; if either differs, STOP and report. Do NOT check out local `develop` (it has diverged from 36e0dd1). Do NOT push. Do NOT run any `git add`/`git commit` in the thirdparty superproject — the gitlink bump there is orchestrator-owned (see "Orchestrator-owned follow-ups" below). + +git -C AsyncIOManager checkout -b dev_ipfsdevice_retry_uaf # branch off 36e0dd1; matches repo's dev_* naming (dev_bitswapdht, dev_holepunching) +git -C AsyncIOManager add src/IPFSCommon.cpp test/src/ipfs_device_test.cpp test/src/CMakeLists.txt +git -C AsyncIOManager status --short # MUST list exactly those three files, nothing else +git -C AsyncIOManager commit -m "Fix use-after-free in IPFSDevice::StartFindingPeersWithRetry: capture shared_from_this in dhtretry_ timer handler and remove dead local timer" + +Record the new commit hash for the orchestrator. + + + cd /Users/Shared/SSDevelopment/Development/GeniusVentures/GeniusNetwork/thirdparty/AsyncIOManager && git rev-parse --short HEAD && git branch --show-current | grep -x dev_ipfsdevice_retry_uaf && git show --stat --oneline HEAD | grep -c 'IPFSCommon.cpp\|ipfs_device_test' | grep -x 2 && git status --short | wc -l | grep -x 0 && echo COMMIT-OK + + Library builds and installs from build/OSX/Debug; ipfs_device_test passes 2/2 (including the pre-fix-failing weak_ptr assertion); the three always-on test targets pass; submodule has one new commit on branch dev_ipfsdevice_retry_uaf off 36e0dd1 containing exactly the three files, working tree clean, nothing pushed. + + + + + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| async timer handler → IPFSDevice | handler runs on an io thread after the caller may have destroyed the device; raw `this` dereference crosses a lifetime boundary | +| process-global FileManager singleton → IPFSDevice | re-`setBitswap` releases the previous device while its retry timer may still be armed | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Disposition | Mitigation Plan | +|-----------|----------|-----------|-------------|-----------------| +| T-GJ4-01 | Tampering / DoS (use-after-free) | IPFSDevice::StartFindingPeersWithRetry dhtretry_ handler | mitigate | Task 1: capture `shared_from_this()` in the async_wait lambda; handler holds a strong reference for the timer's lifetime (mirrors RequestBlockMain pattern) | +| T-GJ4-02 | Denial of Service | retry loop on empty provider lists | accept | Pre-convergence DHT behavior the retry is designed to ride out; explicitly out of scope per user (scope guard in context) | +| T-GJ4-03 | Tampering | package installs | accept | No new dependencies — fix and tests use only existing thirdparty libs (boost::asio, gtest, libp2p, ipfs-bitswap-cpp) | + + + +1. `git -C AsyncIOManager diff 36e0dd1..HEAD -- src/IPFSCommon.cpp` shows changes confined to `StartFindingPeersWithRetry` (lines 154-179 region) and nothing else. +2. `AsyncIOManager/build/OSX/DebugTests/test_bin/ipfs_device_test` passes 2/2 — and the `RetryTimerKeepsDeviceAlive` assertion is the demonstrated regression signal (fails on unfixed code, passes after). +3. `ctest` in DebugTests passes mnn_loader_test, mnn_saver_test, filemanager_test (shared-library regressions). +4. Canonical `build/OSX/Debug` produced and installed the AsyncIOManager library. +5. Submodule: one commit on `dev_ipfsdevice_retry_uaf` off `36e0dd1`, exactly three files, clean tree, not pushed; thirdparty superproject NOT committed by the executor. + + + +- The armed `dhtretry_` handler keeps its IPFSDevice alive until it completes — verified by a weak_ptr that does not expire while the timer is pending (Test 1) and by the full retry chain completing after the external reference is dropped (Test 2). +- Dead local timer removed; no other production behavior changed. +- Builds green in both build dirs; all existing tests green; regression test green. +- Submodule commit lands on a new branch off 36e0dd1; no push; no superproject commit by the executor. + + + +NOT executor work — the executor must NOT perform these steps: +1. Thirdparty superproject gitlink bump: `git add AsyncIOManager` + commit on the superproject's `develop` branch, referencing the submodule commit hash reported by the executor. +2. Any documentation/summary writes outside the AsyncIOManager submodule. + + + +Report back: new submodule commit hash and branch name, test results for ipfs_device_test and the three ctest targets, and confirmation that build/OSX/Debug produced the installed library. Do not write report files — return findings as the final message. + diff --git a/.planning/quick/260829-gj4-fix-use-after-free-in-ipfsdevice-startfi/260829-gj4-SUMMARY.md b/.planning/quick/260829-gj4-fix-use-after-free-in-ipfsdevice-startfi/260829-gj4-SUMMARY.md new file mode 100644 index 00000000..bbabf941 --- /dev/null +++ b/.planning/quick/260829-gj4-fix-use-after-free-in-ipfsdevice-startfi/260829-gj4-SUMMARY.md @@ -0,0 +1,104 @@ +--- +status: complete +phase: quick-260829-gj4 +plan: 01 +subsystem: AsyncIOManager +requirement: GJ4-UAF-01 +submodule_commit: 6f4f5ce +submodule_branch: dev_ipfsdevice_retry_uaf +base_commit: 36e0dd1 +started: 2026-08-29T19:05:59Z +completed: 2026-08-29T19:22:19Z +duration: ~16 min +tags: [ipfs, use-after-free, async, boost-asio, regression-test] +--- + +# Quick Task 260829-gj4: Fix use-after-free in IPFSDevice::StartFindingPeersWithRetry + +One-liner: The 10s `dhtretry_` timer handler in `StartFindingPeersWithRetry` now captures `shared_from_this()` (mirroring the `RequestBlockMain` pattern), the dead local timer is removed, and a new gated regression test proves it: pre-fix code segfaults, post-fix code passes 2/2. + +## Result + +**Status: COMPLETE.** All three tasks executed; single atomic commit `6f4f5ce` on branch `dev_ipfsdevice_retry_uaf` (off `36e0dd1`) inside the AsyncIOManager submodule; nothing pushed; no superproject commit made by the executor. + +## What Changed + +### 1. `AsyncIOManager/src/IPFSCommon.cpp` — the fix (lines 154-180, single diff hunk) + +Four surgical changes inside `IPFSDevice::StartFindingPeersWithRetry`, nothing else in the file (verified: `git diff 36e0dd1..HEAD -- src/IPFSCommon.cpp` is one hunk, `@@ -159,21 +159,22 @@`): + +- DELETED line 162: dead local `boost::asio::deadline_timer dhtretry( *ioc.get() );` (constructed, never used). +- INSERTED after `dhtretry_.expires_from_now( timeout );`: `auto self = shared_from_this();` with the house comment "Capture shared_ptr to keep this object alive during callback" (mirrors lines 192-196 in `RequestBlockMain`). +- Lambda capture list: trailing `this` replaced with `self`. +- Both branches routed through `self->` (`self->StartFindingPeers(...)` in the timeout branch; `self->m_logger->error(...)` in the error branch). + +No destructor `dhtretry_.cancel()` added (per plan rationale: with self-capture the destructor cannot run while a handler is pending; member destruction already cancels outstanding waits). Pre-existing `10000` ms literal left untouched per scope guard. + +### 2. `AsyncIOManager/test/src/ipfs_device_test.cpp` — new regression tests (136 lines) + +- Fixture `IPFSDeviceRetryTest : public ::testing::Test` with one client-only `BitswapNode` (suite-static, `GTEST_SKIP()` on construction failure, no `FileManagerTestFixture` base, no disk access). +- `RetryTimerKeepsDeviceAlive`: arms the timer, drops the last external `shared_ptr`, asserts `EXPECT_NE(watch.lock(), nullptr)`, then deterministically waits out the timer via `pollUntil(watch.expired(), 20s)`. +- `RetryChainCompletesAfterReferenceDropped`: arms first, drops the reference, asserts the completion callback fires within 20s via `pollUntil` and that the result is the expected failure (`Error::CANNOT_DECODE` path), then confirms `watch.expired()`. +- All waits via `pollUntil` (project wait-condition template); zero `sleep_for`; Allman braces; `kNeverPublishedCid` named constant. + +### 3. `AsyncIOManager/test/src/CMakeLists.txt` — target registration (lines 168-200) + +`addtest(ipfs_device_test ...)` block inside the `if(ASYNC_IO_MANAGER_NETWORK_TESTS)` gate, after the `ipfs_saver_test` block; link libraries byte-identical to `ipfs_loader_test`; plus one `target_compile_options` addition (see Deviation 7). + +## Test Results + +| Test | Result | +|---|---| +| `ipfs_device_test` (new) | **2/2 PASSED** (`RetryTimerKeepsDeviceAlive` 10010 ms, `RetryChainCompletesAfterReferenceDropped` 10046 ms) | +| `ctest -R "mnn_loader_test\|mnn_saver_test\|filemanager_test"` | **3/3 Passed, 0 failed** (8.47s total) | + +**TDD RED/GREEN evidence** (Task 1 was `tdd="true"` but the plan commits fix+tests atomically, so the RED gate was demonstrated post-hoc by temporarily restoring `36e0dd1`'s `IPFSCommon.cpp` and rebuilding): + +- RED (pre-fix): `./test_bin/ipfs_device_test --gtest_filter=IPFSDeviceRetryTest.RetryTimerKeepsDeviceAlive` → **Segmentation fault: 11 (exit 139)** — the actual use-after-free, matching the crash reports (fault in the timer handler on freed memory). +- GREEN (post-fix): same test → `[ PASSED ] 1 test` (10024 ms); full binary 2/2. The fixed source was then restored via `git checkout -- src/IPFSCommon.cpp` and rebuilt; tracked tree clean. + +## Build Results + +Both build dirs use the plan's prescribed entry point (`build/OSX/CMakeLists.txt`, Ninja, Debug, x86_64 pin at line 22) plus the workspace's own cache args (see Deviations 2-4): + +- **`build/OSX/Debug` (canonical)**: configured, `ninja AsyncIOManager` → `[15/15] Linking CXX static library AsyncIOManager/lib/libAsyncIOManager.a` (~80 MB), `ninja install` installed headers + `lib/cmake/Async/*` into the build prefix. CONFIRMED. +- **`build/OSX/DebugTests`**: configured with `-DASYNC_IO_MANAGER_NETWORK_TESTS=ON`; built `ipfs_device_test`, `mnn_loader_test`, `mnn_saver_test`, `filemanager_test` — all four compile and link clean. + +## Submodule Git State + +- Commit: `6f4f5ce` — "Fix use-after-free in IPFSDevice::StartFindingPeersWithRetry: capture shared_from_this in dhtretry_ timer handler and remove dead local timer" +- Branch: `dev_ipfsdevice_retry_uaf`, created off `36e0dd1` (guard verified before branching: HEAD `36e0dd1`, detached, clean) +- Files: exactly `src/IPFSCommon.cpp`, `test/src/ipfs_device_test.cpp`, `test/src/CMakeLists.txt` (175 insertions, 4 deletions) +- Not pushed. No `git add`/`commit` in the thirdparty superproject. Working tree: zero tracked modifications; `?? build/OSX/DebugTests/` untracked as expected (not gitignored, not committed, no `git clean` run). + +## Deviations from Plan + +**1. [Rule 1 - test bug] `s_clientNode` access section.** Plan specified `private static std::unique_ptr s_clientNode;`, but gtest `TEST_F` subclasses cannot access private base members — compile error `'s_clientNode' is a private member of 'IPFSDeviceRetryTest'`. Changed the section to `protected:`, matching the reference fixture (`IPFSIntegrationTest` keeps its statics accessible). Files: `test/src/ipfs_device_test.cpp`. + +**2. [Rule 3 - blocking env issue] `-DTHIRDPARTY_DIR=` required.** The plan's bare `cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Debug` fails: `CommonCompilerOptions.CMake:67 Cannot find thirdparty directory required to build`. The script's default only auto-resolves when a sibling `thirdparty/` exists next to the checkout (standalone layout) — not this workspace's layout (AsyncIOManager is nested inside the superproject named `thirdparty`). `THIRDPARTY_DIR` is the script's own first-class cache knob (`if (NOT DEFINED THIRDPARTY_DIR)`), and the value chosen (superproject root) is exactly what the superproject itself sets for the same variable (`build/CommonCompilerOptions.cmake:123`). `THIRDPARTY_BUILD_DIR` then auto-defaults to `/build/OSX/Debug`, where every dependency is installed. No change to generator, toolchain, arch, or entry point. + +**3. [Rule 3 - blocking env issue] OpenSSL cache args required (`-DOpenSSL_DIR`, `-DOPENSSL_ROOT_DIR`, `-DOPENSSL_USE_STATIC_LIBS`).** Without them, `find_package(OpenSSL)` in CONFIG mode (the script sets `CMAKE_FIND_PACKAGE_PREFER_CONFIG ON`) fell through to Homebrew's OpenSSL (`OpenSSL_DIR=/opt/homebrew/lib/cmake/OpenSSL`), which leaked `-isystem /opt/homebrew/include` onto every compile line — ahead of the thirdparty `fmt/include` — so `#include ` resolved to Homebrew fmt 12.1.0, breaking spdlog 1.12 (`spdlog/common.h:373: no template named 'basic_format_string' in namespace 'fmt'`). The three flags are copied verbatim from the superproject's own `_OPENSSL_CACHE_ARGS` (`build/OSX/CMakeLists.txt:125-129`) that it passes to AsyncIOManager via ExternalProject. With them, no `/opt/homebrew` path appears on any compile line. + +**4. [Rule 3 - pre-existing out-of-scope failure] `-DBUILD_EXAMPLES=OFF`.** `ninja install` builds the example target, and `example/MNNExample.cpp:168` fails under the installed Xcode 26.2 clang (`-Wmissing-template-arg-list-after-template-kw`, error by default) — a pre-existing conformance issue unrelated to this fix (the library itself compiled 15/15 clean). The superproject's `_CMAKE_COMMON_CACHE_ARGS` already builds AsyncIOManager with `-DBUILD_EXAMPLES:BOOL=OFF`, so this mirrors existing workspace wiring. The example file itself was NOT modified (out of scope; logged here for the verifier). + +**5. [Rule 3 - plan command bug] DebugTests configured without `-DBUILD_TESTING=ON`.** The plan's DebugTests configure command trips a latent double-add in the existing build files: `src/CMakeLists.txt:52` (`if(BUILD_TESTING) add_subdirectory(../test ${CMAKE_BINARY_DIR}/test)`) AND `build/CommonBuildParameters.cmake:323` (`if (TESTING)` — default ON — `add_subdirectory(${PROJECT_ROOT}/test ${CMAKE_BINARY_DIR}/test)`) both claim the same binary dir → CMake fatal error "The binary directory .../DebugTests/test is already used". Since editing the build files is out of scope (three-file commit limit), DebugTests was configured with `BUILD_TESTING` left at its default OFF: the `TESTING` option (default ON) is what adds the test subdir and calls `enable_testing()`, so all four prescribed targets build and ctest registers everything (`Test #1/#2/#3/#8`). No behavioral difference for the plan's verification steps. + +**6. [verify-script quirk] Task 1's verify one-liner.** `grep -n ... | wc -l | grep -x 2` can never match on macOS because `wc -l` pads output with spaces. Re-ran the same assertions with `grep -c` — all three underlying assertions pass (dead local gone: 0; `self = shared_from_this`: 2; `handle_read, this]`: 0). Task 2's and Task 3's verify one-liners ran as written (Task 3's `git status --short | wc -l | grep -x 0` is satisfied in spirit: zero tracked modifications; the `?? build/OSX/DebugTests/` untracked entry is expected per orchestrator instructions). + +**7. [Rule 3 - pre-existing toolchain drift] `-Wno-missing-template-arg-list-after-template-kw` on the new target.** Shared header `test/testutil/bitswap_node.hpp:99` (Boost.DI `TEMPLATE_TO` macro) trips the same newer-clang default-error conformance warning as Deviation 4's example file — affecting all bitswap-node-based tests on this toolchain, not just the new one. Added `target_compile_options(ipfs_device_test PRIVATE -Wno-missing-template-arg-list-after-template-kw)` in `test/src/CMakeLists.txt` (within the allowed file set), scoped to the new target only, consistent with the project's existing `-Wno-*` handling of toolchain noise in `CommonCompilerOptions.CMake`. The shared header itself was NOT modified. + +## Authentication Gates + +None. + +## Known Stubs + +None — no stub patterns in the new/modified files; the failure chain asserted by Test 2 is fully wired end-to-end. + +## Threat Flags + +None. The plan's `` mitigation T-GJ4-01 is implemented and verified (armed handler holds a strong reference; regression test proves it). No new trust-boundary surface introduced. + +## Self-Check: PASSED + +All three committed files exist on disk; commit `6f4f5ce` exists at HEAD of `dev_ipfsdevice_retry_uaf`, exactly 1 commit ahead of `36e0dd1` (ancestor check OK); zero tracked modifications in the submodule; no superproject commits made by the executor; SUMMARY.md present. From 52158b063a9ab67a92aea6e79aff57277ba1f1c1 Mon Sep 17 00:00:00 2001 From: Super Genius Date: Sat, 29 Aug 2026 15:04:55 -0700 Subject: [PATCH 38/62] Update asiomgr with StartFindingPeers FindProviders use-after-free fix --- AsyncIOManager | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AsyncIOManager b/AsyncIOManager index 6f4f5ce4..6dbad925 160000 --- a/AsyncIOManager +++ b/AsyncIOManager @@ -1 +1 @@ -Subproject commit 6f4f5ce4c0aa2c5a260862edb384563ab98edb6a +Subproject commit 6dbad9257d775bc8a49f7aa3a5d9941fcd8fb73d From f481085aa016099575c38b3b190f6a5508d6e557 Mon Sep 17 00:00:00 2001 From: Super Genius Date: Sat, 29 Aug 2026 15:05:05 -0700 Subject: [PATCH 39/62] docs(quick-260829-kov): plan, summary and state tracking for FindProviders UAF fix --- .planning/STATE.md | 3 +- .../260829-kov-PLAN.md | 66 +++++++++++++++++++ .../260829-kov-SUMMARY.md | 61 +++++++++++++++++ 3 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 .planning/quick/260829-kov-fix-second-use-after-free-raw-this-in-dh/260829-kov-PLAN.md create mode 100644 .planning/quick/260829-kov-fix-second-use-after-free-raw-this-in-dh/260829-kov-SUMMARY.md diff --git a/.planning/STATE.md b/.planning/STATE.md index 24cc3b6f..988ca7e4 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -8,5 +8,6 @@ | # | Description | Date | Commit | Directory | |---|-------------|------|--------|-----------| | 260829-gj4 | Fix use-after-free in IPFSDevice::StartFindingPeersWithRetry (AsyncIOManager): capture shared_from_this in dhtretry_ timer handler; regression test ipfs_device_test | 2026-08-29 | AsyncIOManager@6f4f5ce (dev_ipfsdevice_retry_uaf) | [260829-gj4-fix-use-after-free-in-ipfsdevice-startfi](./quick/260829-gj4-fix-use-after-free-in-ipfsdevice-startfi/) | +| 260829-kov | Fix second use-after-free in IPFSDevice::StartFindingPeers (AsyncIOManager): capture shared_from_this in FindProviders callback; regression test seeds kademlia peer for genuinely-async query | 2026-08-29 | AsyncIOManager@6dbad92 (dev_ipfsdevice_retry_uaf) | [260829-kov-fix-second-use-after-free-raw-this-in-dh](./quick/260829-kov-fix-second-use-after-free-raw-this-in-dh/) | -Last activity: 2026-08-29 - Completed quick task 260829-gj4: Fix use-after-free in IPFSDevice::StartFindingPeersWithRetry (AsyncIOManager) +Last activity: 2026-08-29 - Completed quick task 260829-kov: Fix second use-after-free in IPFSDevice::StartFindingPeers FindProviders callback (AsyncIOManager) diff --git a/.planning/quick/260829-kov-fix-second-use-after-free-raw-this-in-dh/260829-kov-PLAN.md b/.planning/quick/260829-kov-fix-second-use-after-free-raw-this-in-dh/260829-kov-PLAN.md new file mode 100644 index 00000000..d68c94c3 --- /dev/null +++ b/.planning/quick/260829-kov-fix-second-use-after-free-raw-this-in-dh/260829-kov-PLAN.md @@ -0,0 +1,66 @@ +--- +phase: quick-260829-kov +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: + - AsyncIOManager/src/IPFSCommon.cpp + - AsyncIOManager/test/src/ipfs_device_test.cpp +autonomous: true +requirements: [KOV-UAF-02] +--- + +# Quick Task 260829-kov: Fix second UAF — raw `this` in `dht_->FindProviders` lambda + +Follow-up to 260829-gj4 (same class of defect, different lambda). With the DHT actually +started (`auto_dht=true` in GT), the provider query runs ~20s async; on completion the +callback runs on a freed IPFSDevice. Crash report `content_exchange_test-2026-08-29-134615.ips`, +fault 0x38, frames `kademlia::FindProvidersExecutor::done() → callback → m_logger->error("Empty provider list received")`. + +**The bug (verified):** `IPFSDevice::StartFindingPeers` (src/IPFSCommon.cpp:118-149) passes a +`[=]`-capture lambda to `dht_->FindProviders` — `[=]` copies raw `this`. Member derefs inside: +`m_logger->error` (:124, :145), `addAddresses` (:139), `RequestBlockMain` (:141), +`StartFindingPeersWithRetry` (:146). Nothing holds the device while the query is in flight. + +**Verified async semantics:** `IpfsDHT::FindProviders` → `kademlia_->findProviders` → with an +empty content-routing table the handler is stored in an async `GetProvidersExecutor` +(libp2p kademlia_impl.cpp:216-219) — never invoked synchronously. So a pending query holds +the callback (and post-fix, its `self` capture) until the DHT stack is torn down. + +## Fix (user-specified; mirrors 6f4f5ce / RequestBlockMain pattern) + +In `StartFindingPeers`, before `dht_->FindProviders(`: +`// Capture shared_ptr to keep this object alive during callback` + `auto self = shared_from_this();` +Replace `[=]` with `[self, ioc, cid, filename, addressoffset, parse, save, handle_read]` and route +every member access through `self->` (including `self->RequestBlockMain` at :141 — required to +compile once `this` is no longer captured). Nothing else in the file changes. The unused +`peer_id` local (:117) is pre-existing and stays (out of scope). + +## Regression test (extend `test/src/ipfs_device_test.cpp`, no CMake change — kademlia + ipld_node already linked) + +`IPFSDeviceRetryTest.FindProvidersCallbackKeepsDeviceAlive` — instant, deterministic: +1. Build a minimal DHT stack mirroring IPFSDevice's singleton ctor: kademlia via + `makeHostInjector(makeKademliaInjector(useKademliaConfig(default Config)))`, `IpfsDHT(kademlia, {}, runner.ioc())` + — no bootstrap addresses (hermetic; query stays pending forever, never touches network). +2. `device = createWithBitswap(runner.ioc(), suiteNode->getBitswap(), dht)`; call + `StartFindingPeers(...)` (takes the DHT branch, arms the async query). +3. `weak_ptr watch = device; device.reset();` — drops the last external ref mid-query (the UAF window). +4. `EXPECT_NE(watch.lock(), nullptr)` — pre-fix (`[=]` = raw this) FAILS instantly; post-fix the + executor-stored callback holds `self`. +5. No expiry wait: a pending query legitimately keeps the device alive; teardown is by scope + (dht/kademlia/host die before runner → callback destroyed → device dtor on the test thread). + +## Build & verify + +- Canonical `build/OSX/Debug`: incremental `ninja AsyncIOManager && ninja install` (configure flags + from 260829-gj4 SUMMARY: THIRDPARTY_DIR + OpenSSL cache args + BUILD_EXAMPLES=OFF). +- `build/OSX/DebugTests`: rebuild, run `test_bin/ipfs_device_test` (3 tests), `ctest -R "mnn_loader_test|mnn_saver_test|filemanager_test"`. +- RED/GREEN: run the new test against the pre-fix IPFSCommon.cpp (checkout 6f4f5ce's copy), expect + the weak_ptr assertion to FAIL; restore fix, expect pass. + +## Commits + +1. Inside AsyncIOManager on existing branch `dev_ipfsdevice_retry_uaf` (stacked on 6f4f5ce), + exactly two files. No push. +2. Orchestrator: thirdparty gitlink bump + docs (this PLAN, SUMMARY, STATE.md row). diff --git a/.planning/quick/260829-kov-fix-second-use-after-free-raw-this-in-dh/260829-kov-SUMMARY.md b/.planning/quick/260829-kov-fix-second-use-after-free-raw-this-in-dh/260829-kov-SUMMARY.md new file mode 100644 index 00000000..0cca32b1 --- /dev/null +++ b/.planning/quick/260829-kov-fix-second-use-after-free-raw-this-in-dh/260829-kov-SUMMARY.md @@ -0,0 +1,61 @@ +--- +phase: quick-260829-kov +status: complete +started: 2026-08-29 +completed: 2026-08-29 +requirements: [KOV-UAF-02] +--- + +# Quick Task 260829-kov — SUMMARY + +**Fix second UAF — raw `this` in the `dht_->FindProviders` lambda (AsyncIOManager)** +Status: **COMPLETE** · Commit: `AsyncIOManager@6dbad92` (branch `dev_ipfsdevice_retry_uaf`, stacked on `6f4f5ce`) + +## What changed (2 files, +76/−13) + +- **`src/IPFSCommon.cpp`** — `StartFindingPeers`: `auto self = shared_from_this();` before the + call; `[=]` replaced with `[self, ioc, cid, filename, addressoffset, parse, save, handle_read]`; + all member accesses routed through `self->` (`m_logger` ×2, `addAddresses`, `RequestBlockMain`, + `StartFindingPeersWithRetry`). Mirrors the `RequestBlockMain`/`6f4f5ce` house pattern. No other + code touched. +- **`test/src/ipfs_device_test.cpp`** — new `FindProvidersCallbackKeepsDeviceAlive`; file header + `@brief` updated to cover both UAF lambdas. No CMake change (kademlia/ipld_node already linked). + +## The regression test — key finding + +The first version of the test asserted against an **empty** kademlia routing table and PASSED even +pre-fix. Root cause of the false negative: `FindProvidersExecutor::spawn()` calls `done()` +synchronously when `requests_in_progress_ == 0` (libp2p find_providers_executor.cpp), so with an +empty table the handler runs on the caller thread *inside* `StartFindingPeers` — before the +external reference is dropped, and the (already-fixed) retry timer then holds the device. + +The committed test seeds **one unreachable peer** (`kademlia->addPeer`, PeerId derived via +`PeerId::fromHash(cid.content_address)` — the same call production code makes) so `newStream()` +dials asynchronously: the handler stays stored in the executor across `device.reset()`, which is +the in-flight window the GT crash hit. Hermetic — the dial pends on the unrun libp2p io_context; +nothing leaves the process. + +## Verification + +| Step | Result | +|---|---| +| RED — pre-fix source (6f4f5ce) + seeded-peer test | FAILED in 5ms: "device was freed while FindProviders query was in flight (use-after-free)" | +| GREEN — fix restored, full `ipfs_device_test` | 3/3 PASSED (`RetryTimer*` 10055/10047ms, `FindProvidersCallback*` 5ms) | +| Canonical build `build/OSX/Debug` | `ninja AsyncIOManager && ninja install` clean | +| Dependent suites (DebugTests ctest) | `mnn_loader_test` + `mnn_saver_test` + `filemanager_test` — 100% passed, 0 failed | + +Build flags per `260829-gj4-SUMMARY.md` (THIRDPARTY_DIR + OpenSSL cache args + BUILD_EXAMPLES=OFF; +`TESTING` option, not the double-add `BUILD_TESTING`). + +## Commits + +- `AsyncIOManager@6dbad92` — fix + test, branch `dev_ipfsdevice_retry_uaf` (stacks on `6f4f5ce`) +- thirdparty — gitlink bump + docs (this PLAN/SUMMARY, STATE.md row) + +Nothing pushed. User verification step (GT): rebuild `content_exchange_test` with `auto_dht=true` — +should now survive the ~20s provider-query completion (`Empty provider list received` logged, retry +re-armed) instead of SIGSEGV. + +## Deviations + +- None this round. (Round 1's documented roadmap/deviation notes still apply to the task family.) From 3851c3b5b60d6c3fed918505590404a9294e6dd0 Mon Sep 17 00:00:00 2001 From: Super Genius Date: Sat, 29 Aug 2026 19:09:10 -0700 Subject: [PATCH 40/62] udpating AsyncIOManager for ipfs loaders/saver to use bitswap --- AsyncIOManager | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AsyncIOManager b/AsyncIOManager index 6dbad925..9294aea4 160000 --- a/AsyncIOManager +++ b/AsyncIOManager @@ -1 +1 @@ -Subproject commit 6dbad9257d775bc8a49f7aa3a5d9941fcd8fb73d +Subproject commit 9294aea4892db66a2c77a87e6fd40e9a1da5e759 From abbf923a136ba7cde50fea56c03728bfa0552374 Mon Sep 17 00:00:00 2001 From: Eduardo Menges Mattje Date: Mon, 31 Aug 2026 12:40:08 -0300 Subject: [PATCH 41/62] Fixed Windows builds --- .github/workflows/build.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 328d7ef0..cc1fc923 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -163,11 +163,13 @@ jobs: - name: Configure bash on Windows (use Git Bash, not WSL) if: ${{ runner.environment == 'self-hosted' && matrix.target == 'Windows' }} run: | - foreach ($p in @("C:\Program Files\Git\bin", "C:\Program Files\Git\usr\bin")) { - if (Test-Path $p) { - Add-Content -Path $env:GITHUB_PATH -Value $p - $env:PATH = "$p;$env:PATH" - } + # Only put Git\bin on PATH (it has bash.exe). Do NOT add Git\usr\bin: + # its trimmed MSYS2 perl shadows Strawberry Perl and breaks the + # OpenSSL Configure step (missing Locale::Maketext::Simple). + $gitBinPath = "C:\Program Files\Git\bin" + if (Test-Path $gitBinPath) { + Add-Content -Path $env:GITHUB_PATH -Value $gitBinPath + $env:PATH = "$gitBinPath;$env:PATH" } $bash = (Get-Command bash.exe -ErrorAction SilentlyContinue).Source Write-Output $(if ($bash) { "Bash location: $bash" } else { "WARNING: bash.exe not found in PATH" }) From 011e551b1c51fe0f09247e92f43e56aad6f69b5b Mon Sep 17 00:00:00 2001 From: Eduardo Menges Mattje Date: Mon, 31 Aug 2026 12:54:23 -0300 Subject: [PATCH 42/62] Fixed `BYPRODUCTS` keyword --- build/CommonTargets.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/CommonTargets.cmake b/build/CommonTargets.cmake index 808f3e75..4db99654 100644 --- a/build/CommonTargets.cmake +++ b/build/CommonTargets.cmake @@ -411,7 +411,7 @@ if(NOT APPLE OR (APPLE AND CMAKE_OSX_SYSROOT MATCHES "iPhoneOS")) ${_CMAKE_COMMON_CACHE_ARGS} ${_MNN_EXTRA_PARAM} DEPENDS ${_MNN_DEPENDS} ${vulkanTarget} - BYPRODUCTS + BUILD_BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/MNN/lib/${CMAKE_STATIC_LIBRARY_PREFIX}MNN${CMAKE_STATIC_LIBRARY_SUFFIX}" ${MNN_TEST_BYPRODUCT} ) From 8e7c5f5f7758bdbc3934a36b082dee6331370fa1 Mon Sep 17 00:00:00 2001 From: Eduardo Menges Mattje Date: Mon, 31 Aug 2026 13:48:51 -0300 Subject: [PATCH 43/62] Fixed MNN for iOS --- MNN | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MNN b/MNN index 84b4cac8..ba67ae28 160000 --- a/MNN +++ b/MNN @@ -1 +1 @@ -Subproject commit 84b4cac8d60633ae5ed94149732ddf814bbb2e2f +Subproject commit ba67ae2820089a4ceddc1fe6e38a74bf28e7cb31 From 00d5081ca44eacec29bc404c4dd0a9bb521d5733 Mon Sep 17 00:00:00 2001 From: Super Genius Date: Mon, 31 Aug 2026 12:37:07 -0700 Subject: [PATCH 44/62] updated references for main develop branch of thirdparty --- AsyncIOManager | 2 +- MNN | 2 +- ipfs-bitswap-cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/AsyncIOManager b/AsyncIOManager index 9294aea4..7f09fc84 160000 --- a/AsyncIOManager +++ b/AsyncIOManager @@ -1 +1 @@ -Subproject commit 9294aea4892db66a2c77a87e6fd40e9a1da5e759 +Subproject commit 7f09fc8496d5cd53a9e8dd5c2ed648ae3c49631c diff --git a/MNN b/MNN index ba67ae28..84b4cac8 160000 --- a/MNN +++ b/MNN @@ -1 +1 @@ -Subproject commit ba67ae2820089a4ceddc1fe6e38a74bf28e7cb31 +Subproject commit 84b4cac8d60633ae5ed94149732ddf814bbb2e2f diff --git a/ipfs-bitswap-cpp b/ipfs-bitswap-cpp index 73092a88..d2ec18af 160000 --- a/ipfs-bitswap-cpp +++ b/ipfs-bitswap-cpp @@ -1 +1 @@ -Subproject commit 73092a880514da338fe16c942f4dcca3fdce55e1 +Subproject commit d2ec18afd1ed397c7f5f79945a3da76fca49c1f6 From a0b0fd11c14fa9b7aa927aaf85c1b9c56b8ddd1f Mon Sep 17 00:00:00 2001 From: Eduardo Menges Mattje Date: Mon, 31 Aug 2026 16:50:37 -0300 Subject: [PATCH 45/62] Fix teardown in `soralog` --- soralog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soralog b/soralog index a77e0bf2..9e34ec1e 160000 --- a/soralog +++ b/soralog @@ -1 +1 @@ -Subproject commit a77e0bf2a7bc1b7e25fc21e955965f0f021baa61 +Subproject commit 9e34ec1e40adaca338097cf03404135e0afabb0b From daa9e58540980478864ac8d1741fd5eb07272322 Mon Sep 17 00:00:00 2001 From: Eduardo Menges Mattje Date: Mon, 31 Aug 2026 17:19:35 -0300 Subject: [PATCH 46/62] Restored MNN iOS Vulkan link fix in submodule reference The reference bot commit ("updated references") moved MNN back to 84b4cac, which predates the MoltenVK framework linking fix, so the iOS CI failed with undefined ObjC/Foundation/QuartzCore symbols when linking MNN's LLM demos against libMoltenVK.a. Point MNN at the fork tip, which additionally links UIKit (iOS) and the objc runtime. Co-Authored-By: Claude --- MNN | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MNN b/MNN index 84b4cac8..2b3d11d7 160000 --- a/MNN +++ b/MNN @@ -1 +1 @@ -Subproject commit 84b4cac8d60633ae5ed94149732ddf814bbb2e2f +Subproject commit 2b3d11d7d16de261b1581c0e748e11c4ab811b80 From 13a0434cda72a287b1a5f7a0efbfbe3c0f878033 Mon Sep 17 00:00:00 2001 From: Super Genius Date: Mon, 31 Aug 2026 16:13:30 -0700 Subject: [PATCH 47/62] fix: bump MNN to install LLM headers on non-Apple platforms MNN a2b29259 adds the missing IF(MNN_BUILD_LLM) INSTALL rule to the ELSEIF(NOT APPLE) branch, so Linux/Android/Windows thirdparty builds ship MNN/llm/llm.hpp alongside libMNN.a (library already contained the Transformer symbols; only the header was dropped). --- MNN | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MNN b/MNN index 2b3d11d7..a2b29259 160000 --- a/MNN +++ b/MNN @@ -1 +1 @@ -Subproject commit 2b3d11d7d16de261b1581c0e748e11c4ab811b80 +Subproject commit a2b2925940bc9c24ae0fdde74e180971301bc99a From 3013ac88db09cfcdcdc92fc5ca967df7274141d4 Mon Sep 17 00:00:00 2001 From: Super Genius Date: Mon, 31 Aug 2026 16:26:38 -0700 Subject: [PATCH 48/62] Revert "fix: bump MNN to install LLM headers on non-Apple platforms" This reverts commit 13a0434cda72a287b1a5f7a0efbfbe3c0f878033. --- MNN | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MNN b/MNN index a2b29259..2b3d11d7 160000 --- a/MNN +++ b/MNN @@ -1 +1 @@ -Subproject commit a2b2925940bc9c24ae0fdde74e180971301bc99a +Subproject commit 2b3d11d7d16de261b1581c0e748e11c4ab811b80 From 40ed7b010711bfab4b73aaf722bdab23b794b03f Mon Sep 17 00:00:00 2001 From: itsafuu Date: Mon, 31 Aug 2026 19:56:29 -0400 Subject: [PATCH 49/62] Bump asiomgr, pubsub, libp2p. This includes pnet code --- AsyncIOManager | 2 +- ipfs-pubsub | 2 +- libp2p | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/AsyncIOManager b/AsyncIOManager index 7f09fc84..009dc3dc 160000 --- a/AsyncIOManager +++ b/AsyncIOManager @@ -1 +1 @@ -Subproject commit 7f09fc8496d5cd53a9e8dd5c2ed648ae3c49631c +Subproject commit 009dc3dc04599c61d04aca5ba0cf547703543b31 diff --git a/ipfs-pubsub b/ipfs-pubsub index 16056368..3294d410 160000 --- a/ipfs-pubsub +++ b/ipfs-pubsub @@ -1 +1 @@ -Subproject commit 16056368f1d6ee33aa1d389cbf2c35dd143a6beb +Subproject commit 3294d410afac6df0d3f50ae95efe41ee4deaa12a diff --git a/libp2p b/libp2p index 1ae9b493..b28eed23 160000 --- a/libp2p +++ b/libp2p @@ -1 +1 @@ -Subproject commit 1ae9b493df08aa8c56c57698328297f1286264d0 +Subproject commit b28eed23ccecc41fba99d1acc2723ed900cbe4e7 From 82f59c538b2fc6823f63f8756b8a87c445fc18dc Mon Sep 17 00:00:00 2001 From: Henrique A Klein Date: Tue, 1 Sep 2026 08:46:49 -0300 Subject: [PATCH 50/62] Fix: ipfs-pubsub submodule corrected --- ipfs-pubsub | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipfs-pubsub b/ipfs-pubsub index 3294d410..bcbc50de 160000 --- a/ipfs-pubsub +++ b/ipfs-pubsub @@ -1 +1 @@ -Subproject commit 3294d410afac6df0d3f50ae95efe41ee4deaa12a +Subproject commit bcbc50de2524a985c03fda3a4baffaf6ce117b61 From 6776aa3988f3cfb6ea1d055476cefce51e571c9f Mon Sep 17 00:00:00 2001 From: Eduardo Menges Mattje Date: Thu, 3 Sep 2026 11:41:11 -0300 Subject: [PATCH 51/62] Fix deadlocks in `ipfs-lite-cpp` --- ipfs-lite-cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipfs-lite-cpp b/ipfs-lite-cpp index 4011803c..56afae0c 160000 --- a/ipfs-lite-cpp +++ b/ipfs-lite-cpp @@ -1 +1 @@ -Subproject commit 4011803cec2381dad5c745a845e871bf1a74b4aa +Subproject commit 56afae0c4f32917dc0f799ce1bf1e89911076a74 From 132e57669aeadf0976ead79952737eafe00cd0cc Mon Sep 17 00:00:00 2001 From: itsafuu Date: Thu, 3 Sep 2026 16:13:26 -0400 Subject: [PATCH 52/62] Update submodules, turn demo builds off --- AsyncIOManager | 2 +- MNN | 2 +- build/CommonTargets.cmake | 1 + ipfs-bitswap-cpp | 2 +- ipfs-lite-cpp | 2 +- ipfs-pubsub | 2 +- libp2p | 2 +- 7 files changed, 7 insertions(+), 6 deletions(-) diff --git a/AsyncIOManager b/AsyncIOManager index 2aea7454..009dc3dc 160000 --- a/AsyncIOManager +++ b/AsyncIOManager @@ -1 +1 @@ -Subproject commit 2aea74540f265dc75333b43a4928c4b93ea5553e +Subproject commit 009dc3dc04599c61d04aca5ba0cf547703543b31 diff --git a/MNN b/MNN index 73a27ee6..13e58e12 160000 --- a/MNN +++ b/MNN @@ -1 +1 @@ -Subproject commit 73a27ee659d403b8361c866b816f528537cfa2e8 +Subproject commit 13e58e12d5d16bc4cf9ef03a5a4fe0414c94a11f diff --git a/build/CommonTargets.cmake b/build/CommonTargets.cmake index aee70b4f..c204a1db 100644 --- a/build/CommonTargets.cmake +++ b/build/CommonTargets.cmake @@ -461,6 +461,7 @@ if(NOT APPLE OR (APPLE AND CMAKE_OSX_SYSROOT MATCHES "iPhoneOS")) -DMNN_BUILD_PROTOBUFFER:BOOL=OFF -DMNN_VULKAN:BOOL=ON -DMNN_WIN_RUNTIME_MT:BOOL=ON + -DMNN_LLM_BUILD_DEMO:BOOL=OFF ${_CMAKE_COMMON_CACHE_ARGS} ${_MNN_EXTRA_PARAM} DEPENDS ${_MNN_DEPENDS} ${vulkanTarget} diff --git a/ipfs-bitswap-cpp b/ipfs-bitswap-cpp index d308c1f6..d2ec18af 160000 --- a/ipfs-bitswap-cpp +++ b/ipfs-bitswap-cpp @@ -1 +1 @@ -Subproject commit d308c1f6457356b1b926c040ff8de6083409bd8f +Subproject commit d2ec18afd1ed397c7f5f79945a3da76fca49c1f6 diff --git a/ipfs-lite-cpp b/ipfs-lite-cpp index fef678c8..4011803c 160000 --- a/ipfs-lite-cpp +++ b/ipfs-lite-cpp @@ -1 +1 @@ -Subproject commit fef678c8d151900170304d7e6bee740924d74d32 +Subproject commit 4011803cec2381dad5c745a845e871bf1a74b4aa diff --git a/ipfs-pubsub b/ipfs-pubsub index 16056368..3294d410 160000 --- a/ipfs-pubsub +++ b/ipfs-pubsub @@ -1 +1 @@ -Subproject commit 16056368f1d6ee33aa1d389cbf2c35dd143a6beb +Subproject commit 3294d410afac6df0d3f50ae95efe41ee4deaa12a diff --git a/libp2p b/libp2p index 1ae9b493..b28eed23 160000 --- a/libp2p +++ b/libp2p @@ -1 +1 @@ -Subproject commit 1ae9b493df08aa8c56c57698328297f1286264d0 +Subproject commit b28eed23ccecc41fba99d1acc2723ed900cbe4e7 From 1c1f024fa21d7ee7617a4c5ae790d98976229d84 Mon Sep 17 00:00:00 2001 From: itsafuu Date: Thu, 3 Sep 2026 16:52:40 -0400 Subject: [PATCH 53/62] Merge MNN --- MNN | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MNN b/MNN index 13e58e12..01b6f314 160000 --- a/MNN +++ b/MNN @@ -1 +1 @@ -Subproject commit 13e58e12d5d16bc4cf9ef03a5a4fe0414c94a11f +Subproject commit 01b6f314493f23570212dd21780744cd7bebf8b8 From 1358f0a6759b0b393aec3ae112fff0bec821b0bd Mon Sep 17 00:00:00 2001 From: Eduardo Menges Mattje Date: Thu, 3 Sep 2026 20:23:26 -0300 Subject: [PATCH 54/62] Bump libp2p and ipfs-pubsub for shutdown/publish fixes - libp2p: Autonat detached threads no longer touch a destroyed instance (SIGSEGV in child_tokens_test on macOS Release). - ipfs-pubsub: batch flush timer can no longer wedge PublishBuffered(). Co-Authored-By: Claude Fable 5.1 --- ipfs-pubsub | 2 +- libp2p | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ipfs-pubsub b/ipfs-pubsub index bcbc50de..0b86219c 160000 --- a/ipfs-pubsub +++ b/ipfs-pubsub @@ -1 +1 @@ -Subproject commit bcbc50de2524a985c03fda3a4baffaf6ce117b61 +Subproject commit 0b86219c4a3ebb664abd422ce4f9b108d5968633 diff --git a/libp2p b/libp2p index b28eed23..9962c799 160000 --- a/libp2p +++ b/libp2p @@ -1 +1 @@ -Subproject commit b28eed23ccecc41fba99d1acc2723ed900cbe4e7 +Subproject commit 9962c799849f5e6ee4922e1f66b6bf1848cdadea From b5c66e4ad5c55fa610d36e460bed41d3fa4dc552 Mon Sep 17 00:00:00 2001 From: itsafuu Date: Thu, 3 Sep 2026 20:03:15 -0400 Subject: [PATCH 55/62] Small change to fix PR workflow run --- .github/workflows/build-targets.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-targets.yml b/.github/workflows/build-targets.yml index 0bfd9a6b..d2d2a4dd 100644 --- a/.github/workflows/build-targets.yml +++ b/.github/workflows/build-targets.yml @@ -158,5 +158,8 @@ jobs: matrix: ${{ needs.prepare.outputs.matrix }} upload: ${{ github.ref_name == 'main' || github.ref_name == 'develop' || inputs.tag != '' }} release-tag: ${{ inputs.tag }} - sgns_enable_release_symbols: ${{ inputs.sgns_enable_release_symbols }} + # inputs.* is empty on pull_request events; the == comparison coerces the + # value to a real boolean so the reusable workflow's boolean input + # validation doesn't reject an empty string. + sgns_enable_release_symbols: ${{ inputs.sgns_enable_release_symbols == true }} secrets: inherit From 69be0fea213dbbe49dd9f53a17f327209657ecb9 Mon Sep 17 00:00:00 2001 From: Eduardo Menges Mattje Date: Fri, 4 Sep 2026 09:35:40 -0300 Subject: [PATCH 56/62] Bump ipfs-lite-cpp for graphsync attribution and threading fixes Co-Authored-By: Claude Fable 5.1 --- ipfs-lite-cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipfs-lite-cpp b/ipfs-lite-cpp index 56afae0c..87766a96 160000 --- a/ipfs-lite-cpp +++ b/ipfs-lite-cpp @@ -1 +1 @@ -Subproject commit 56afae0c4f32917dc0f799ce1bf1e89911076a74 +Subproject commit 87766a96ae913201e04987f96e55a8857c638503 From 37ebd136eb853efabcc4a578a3a74678b0bebf24 Mon Sep 17 00:00:00 2001 From: Eduardo Menges Mattje Date: Fri, 4 Sep 2026 13:24:39 -0300 Subject: [PATCH 57/62] Bump libp2p and ipfs-lite-cpp - libp2p: Autonat joins its background threads (fixes shutdown crash). - ipfs-lite-cpp: graphsync sends requests synchronously again; keeps the block-attribution fix. Co-Authored-By: Claude Fable 5.1 --- ipfs-lite-cpp | 2 +- libp2p | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ipfs-lite-cpp b/ipfs-lite-cpp index 87766a96..a276427d 160000 --- a/ipfs-lite-cpp +++ b/ipfs-lite-cpp @@ -1 +1 @@ -Subproject commit 87766a96ae913201e04987f96e55a8857c638503 +Subproject commit a276427d31cc13f3586d873153e0f93c84ed4696 diff --git a/libp2p b/libp2p index 9962c799..dad22abe 160000 --- a/libp2p +++ b/libp2p @@ -1 +1 @@ -Subproject commit 9962c799849f5e6ee4922e1f66b6bf1848cdadea +Subproject commit dad22abeab02f0db34d83b359f1e107d70c3afdf From 14aa5cb11bac954472e64efd805d126b6f84c96e Mon Sep 17 00:00:00 2001 From: Eduardo Menges Mattje Date: Mon, 7 Sep 2026 13:55:16 -0300 Subject: [PATCH 58/62] chore(ipfs-lite-cpp): bump to graphsync NOT_FOUND fix Pairs with the SuperGenius change that stops handing GraphsyncDAGSyncer itself to graphsync as the service it answers remote requests from. Without this bump a responder that lacks a block answers nothing and the requester waits out its full in-progress timeout. Co-Authored-By: Claude Opus 5 (1M context) --- ipfs-lite-cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipfs-lite-cpp b/ipfs-lite-cpp index a276427d..95dc92cc 160000 --- a/ipfs-lite-cpp +++ b/ipfs-lite-cpp @@ -1 +1 @@ -Subproject commit a276427d31cc13f3586d873153e0f93c84ed4696 +Subproject commit 95dc92cc4d21588a852170731939137d6a301b0f From f1783523e33967a8528a7c7d92e6de714d9952c1 Mon Sep 17 00:00:00 2001 From: itsafuu Date: Tue, 8 Sep 2026 19:03:27 -0400 Subject: [PATCH 59/62] build: enable MNN_USE_SYSTEM_LIB on Android and Windows MNN's dlopen-wrapper mode (the default when MNN_USE_SYSTEM_LIB is off) compiles vulkan_wrapper.cpp with -DMNN_USE_LIB_WRAPPER, defining every vk* name as a global function-pointer VARIABLE -- data/STT_OBJECT symbols inside libMNN.a / MNN.lib. SGProcessors in SuperGenius calls the vk* API directly against the real Vulkan prototypes, so those data definitions collide with its direct call sites at link time: - armeabi-v7a: Thumb BL relocations (R_ARM_THM_CALL) require an STT_FUNC target; lld hard-errors with 'interworking not performed' - arm64-v8a: the same binding silently resolves direct calls to the address of the pointer table -- a latent crash on the shipped path - Windows: same silent data/function binding collision in MNN.lib Android now links the NDK's libvulkan.so stub (STT_FUNC exports, same runtime loader on device); Windows links the thirdparty-built Vulkan-Loader import library. Linux/iOS/OSX already passed MNN_USE_SYSTEM_LIB=ON via _MNN_EXTRA_PARAM, so all platforms are now consistent. --- build/Android/CMakeLists.txt | 13 +++++++++++++ build/Windows/CMakeLists.txt | 17 +++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/build/Android/CMakeLists.txt b/build/Android/CMakeLists.txt index 01842f19..4c9ed3c1 100644 --- a/build/Android/CMakeLists.txt +++ b/build/Android/CMakeLists.txt @@ -173,8 +173,21 @@ set(_rocksdb_EXTRA_PARAM set(_ED25519_RANDOM dev_urandom) # MNN +# MNN_USE_SYSTEM_LIB: link the NDK's libvulkan.so stub directly instead of +# MNN's dlopen wrapper. The wrapper mode (-DMNN_USE_LIB_WRAPPER) defines every +# vk* name as a global function-pointer VARIABLE (data/STT_OBJECT symbols) in +# libMNN.a. SuperGenius's SGProcessors compiles against the real Vulkan +# prototypes and calls vk* directly, so the archive's data definitions collide +# with those call sites: on armeabi-v7a, Thumb BL relocations (R_ARM_THM_CALL) +# require an STT_FUNC target and lld hard-errors ("interworking not +# performed"); on arm64-v8a the same binding silently resolves direct calls to +# the address of the pointer table, which crashes if executed. The NDK stub +# exports proper STT_FUNC symbols, matching how Linux/iOS/OSX already build +# MNN via their _MNN_EXTRA_PARAM. find_package(Vulkan) inside MNN resolves the +# stub from the NDK sysroot under this toolchain. set(_MNN_EXTRA_PARAM -DMNN_BUILD_FOR_ANDROID_COMMAND:BOOL=ON + -DMNN_USE_SYSTEM_LIB:BOOL=ON ) set(_ZKLLVM_EXTRA_PARAM diff --git a/build/Windows/CMakeLists.txt b/build/Windows/CMakeLists.txt index 648b672c..932939fb 100644 --- a/build/Windows/CMakeLists.txt +++ b/build/Windows/CMakeLists.txt @@ -95,6 +95,23 @@ set(_OPENSSL_CACHE_ARGS # ed25519 crypto set(_ED25519_RANDOM bcryptgen) +# MNN +# MNN_USE_SYSTEM_LIB: link the thirdparty-built Vulkan loader directly instead +# of MNN's dlopen wrapper. The wrapper mode (-DMNN_USE_LIB_WRAPPER) defines +# every vk* name as a global function-pointer VARIABLE (data/STT_OBJECT +# symbols) in MNN.lib. SuperGenius's SGProcessors compiles against the real +# Vulkan prototypes and calls vk* directly, so those data definitions collide +# with the call sites at link time (the same collision that hard-errors on +# Android armeabi-v7a). This mirrors Linux/iOS/OSX, which already pass +# MNN_USE_SYSTEM_LIB=ON via _MNN_EXTRA_PARAM. vulkan-1.lib is the import +# library of the Vulkan-Loader ExternalProject (built on all non-Android +# platforms by CommonTargets.cmake). +set(_MNN_EXTRA_PARAM + -DMNN_USE_SYSTEM_LIB:BOOL=ON + -DVulkan_INCLUDE_DIR:PATH=${CMAKE_CURRENT_BINARY_DIR}/Vulkan-Loader/include + -DVulkan_LIBRARY:PATH=${CMAKE_CURRENT_BINARY_DIR}/Vulkan-Loader/lib/vulkan-1.lib +) + set(_ZKLLVM_EXTRA_PARAM -DZKLLVM_BUILD_TRANSPILER_LIB:BOOL=OFF -DZKLLVM_BUILD_EXAMPLES:BOOL=OFF From fa5a793f2614c0864172388ec62493b7eddb2520 Mon Sep 17 00:00:00 2001 From: itsafuu Date: Thu, 10 Sep 2026 20:21:28 -0400 Subject: [PATCH 60/62] fpic for vk bootstrap --- build/CommonTargets.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/build/CommonTargets.cmake b/build/CommonTargets.cmake index dc4c1867..efa4e257 100644 --- a/build/CommonTargets.cmake +++ b/build/CommonTargets.cmake @@ -409,6 +409,7 @@ ExternalProject_Add( -DCMAKE_INSTALL_PREFIX:PATH= -DVulkanHeaders_DIR:PATH=${CMAKE_CURRENT_BINARY_DIR}/Vulkan-Headers/share/cmake/VulkanHeaders -DVK_BOOTSTRAP_TEST:BOOL=OFF + -DVK_BOOTSTRAP_POSITION_INDEPENDENT_CODE:BOOL=ON ${_CMAKE_COMMON_CACHE_ARGS} DEPENDS Vulkan-Headers ) From f8ca3580b9e2252fc034273c2f0f0cb681145ca2 Mon Sep 17 00:00:00 2001 From: Eduardo Menges Mattje Date: Fri, 11 Sep 2026 19:41:55 -0300 Subject: [PATCH 61/62] chore(ipfs-pubsub): bump to retryable publish timeout A publish whose strand wait expired still publishes, so it now reports errc::timed_out instead of PUBLISH_FAILED. Lets SuperGenius keep the transaction queued rather than failing it and demoting the node to SYNCING for a message that was delivered. Co-Authored-By: Claude Opus 5 (1M context) --- ipfs-pubsub | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipfs-pubsub b/ipfs-pubsub index 0b86219c..b8ec224b 160000 --- a/ipfs-pubsub +++ b/ipfs-pubsub @@ -1 +1 @@ -Subproject commit 0b86219c4a3ebb664abd422ce4f9b108d5968633 +Subproject commit b8ec224b161bf5ea0a7c67bbd0c3038181dc3349 From 99e4160d0b4d07b3ff3ede0350d36db45668ce6f Mon Sep 17 00:00:00 2001 From: Henrique A Klein Date: Tue, 15 Sep 2026 12:44:15 -0300 Subject: [PATCH 62/62] build(shaderc): shorten ExternalProject binary dir to fit Windows MAX_PATH The default binary dir (/src/shaderc-build) pushes spirv-tools' MSBuild .tlog paths to 272 chars on Windows, past the 260-char MAX_PATH limit on runners without OS long-path support (MSB3491, seen on SG-I9-WIN11 in PR #116). Build in /scb instead (~250 chars worst case). Install tree and shaderc::shaderc target are unaffected. Co-Authored-By: Claude Code --- build/CommonTargets.cmake | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build/CommonTargets.cmake b/build/CommonTargets.cmake index efa4e257..4ce8e255 100644 --- a/build/CommonTargets.cmake +++ b/build/CommonTargets.cmake @@ -423,6 +423,11 @@ ExternalProject_Add( shaderc PREFIX shaderc SOURCE_DIR "${THIRDPARTY_DIR}/shaderc" + # Short binary dir: the default (/src/shaderc-build) pushes spirv-tools' + # MSBuild .tlog paths past the Windows MAX_PATH (260) limit on runners without + # OS long-path support (worst path 272 -> ~250 chars). The install tree under + # (= /shaderc) and the shaderc::shaderc target are unaffected. + BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/scb" PATCH_COMMAND ${Python3_EXECUTABLE} "${THIRDPARTY_DIR}/shaderc/utils/git-sync-deps" CMAKE_CACHE_ARGS