From 11b193cf3549ca7c12b1c5a6f20e9f6c7387fa48 Mon Sep 17 00:00:00 2001 From: Ahmad Mujahid Date: Sun, 25 Oct 2026 14:51:31 +0400 Subject: [PATCH 1/2] fix(prx): build and export the stubs that eight libraries never shipped The 2026-10-21 split PRs added Export.cpp stub files to seven libraries that have their own CMakeLists.txt, so core/libs/CMakeLists.txt never adds Export.cpp for them and no target compiled the 101 stubs. A title that imports one fails to load instead of throwing on the call. Ngs2, Ngs2.native and AvPlayer.native build with hidden visibility, so their stub files also need default visibility. libSceNgs2 already compiled PendingExports.cpp, but its 6 stubs stayed local. --- core/libs/prx/libSceAgc/CMakeLists.txt | 1 + core/libs/prx/libSceAgc/tests/Platform.cpp | 13 +++++++++++++ core/libs/prx/libSceAgcDriver/CMakeLists.txt | 1 + .../tests/UnsupportedDiagnostics.cpp | 9 +++++++++ core/libs/prx/libSceAudiodec.native/CMakeLists.txt | 1 + core/libs/prx/libSceAvPlayer.native/CMakeLists.txt | 2 ++ core/libs/prx/libSceNgs2.native/CMakeLists.txt | 2 ++ .../libSceNgs2.native/tests/Ngs2HandleErrors.cpp | 12 ++++++++++++ core/libs/prx/libSceNgs2/CMakeLists.txt | 1 + core/libs/prx/libSceNpTrophy2/CMakeLists.txt | 1 + .../prx/libSceNpUniversalDataSystem/CMakeLists.txt | 1 + core/libs/tests/GuestNpTrophy2.cpp | 8 ++++++++ core/libs/tests/GuestNpTrophyData.cpp | 11 +++++++++++ 13 files changed, 63 insertions(+) diff --git a/core/libs/prx/libSceAgc/CMakeLists.txt b/core/libs/prx/libSceAgc/CMakeLists.txt index 9c26307068..d6e1c12d56 100644 --- a/core/libs/prx/libSceAgc/CMakeLists.txt +++ b/core/libs/prx/libSceAgc/CMakeLists.txt @@ -1,4 +1,5 @@ add_library(libSceAgc SHARED EXCLUDE_FROM_ALL + ${CMAKE_CURRENT_SOURCE_DIR}/Export.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Unimplemented.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Acb/src/Control.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Acb/src/Dispatch.cpp diff --git a/core/libs/prx/libSceAgc/tests/Platform.cpp b/core/libs/prx/libSceAgc/tests/Platform.cpp index 5ed2b2aea1..33fa04b752 100644 --- a/core/libs/prx/libSceAgc/tests/Platform.cpp +++ b/core/libs/prx/libSceAgc/tests/Platform.cpp @@ -1,10 +1,12 @@ #include "prx/libSceAgc/Misc/include/Platform.hpp" +#include "prx/libSceAgc/include/Agc.hpp" #include "prx/libc/include/general/VabiMacros.hpp" #include "prx/libc/include/Shutdown.hpp" #include #include #include +#include namespace { @@ -34,12 +36,23 @@ void testRejections() { expectFailure([] { sceAgcGetIsTrinityMode(nullptr); }); } +void testUnimplemented() { + try { + sceAgcSuspendPointAndCheckStatus(); + } catch (const std::runtime_error& error) { + check(std::string(error.what()) == "sceAgcSuspendPointAndCheckStatus not implemented", "sceAgcSuspendPointAndCheckStatus threw"); + return; + } + throw std::runtime_error("sceAgcSuspendPointAndCheckStatus must report that it is not implemented"); +} + } int main() { try { testTrinityMode(); testRejections(); + testUnimplemented(); LibcRunShutdown_nid_postfix(); std::puts("AGC platform tests passed"); return 0; diff --git a/core/libs/prx/libSceAgcDriver/CMakeLists.txt b/core/libs/prx/libSceAgcDriver/CMakeLists.txt index fd47b92142..d68e4df799 100644 --- a/core/libs/prx/libSceAgcDriver/CMakeLists.txt +++ b/core/libs/prx/libSceAgcDriver/CMakeLists.txt @@ -238,6 +238,7 @@ foreach(agcOverlayStage IN ITEMS Vert Frag) endforeach() set(agcDriverSources + ${CMAKE_CURRENT_SOURCE_DIR}/Export.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Unimplemented.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Execution/src/ComputePipelineCapture.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Execution/src/DisplayBuffer.cpp diff --git a/core/libs/prx/libSceAgcDriver/tests/UnsupportedDiagnostics.cpp b/core/libs/prx/libSceAgcDriver/tests/UnsupportedDiagnostics.cpp index 3217dc0eb1..00df156cf9 100644 --- a/core/libs/prx/libSceAgcDriver/tests/UnsupportedDiagnostics.cpp +++ b/core/libs/prx/libSceAgcDriver/tests/UnsupportedDiagnostics.cpp @@ -1,8 +1,17 @@ #include "prx/libSceAgcDriver/include/AgcDriver.hpp" #include "SceTypes.hpp" +#include +#include + int main() { if (sceAgcDriverGetCoredumpAddress() != nullptr) return 1; if (sceAgcDriverSetTargetRingForDiag() != static_cast(0x8A6D0001)) return 2; + try { + sceAgcDriverSetFlip(); + return 3; + } catch (const std::runtime_error& error) { + if (std::string(error.what()) != "sceAgcDriverSetFlip not implemented") return 4; + } return 0; } diff --git a/core/libs/prx/libSceAudiodec.native/CMakeLists.txt b/core/libs/prx/libSceAudiodec.native/CMakeLists.txt index a4e07a5c01..9820917503 100644 --- a/core/libs/prx/libSceAudiodec.native/CMakeLists.txt +++ b/core/libs/prx/libSceAudiodec.native/CMakeLists.txt @@ -1,2 +1,3 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/../libSceAudiodec/AudiodecLibrary.cmake) add_sce_audiodec_library(libSceAudiodec.native) +target_sources(libSceAudiodec.native PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/Export.cpp) diff --git a/core/libs/prx/libSceAvPlayer.native/CMakeLists.txt b/core/libs/prx/libSceAvPlayer.native/CMakeLists.txt index 5ba3ecebdb..b9a16defb7 100644 --- a/core/libs/prx/libSceAvPlayer.native/CMakeLists.txt +++ b/core/libs/prx/libSceAvPlayer.native/CMakeLists.txt @@ -1,2 +1,4 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/../libSceAvPlayer/AvPlayerLibrary.cmake) add_sce_avplayer_library(libSceAvPlayer.native) +target_sources(libSceAvPlayer.native PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/Export.cpp) +set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/Export.cpp PROPERTIES COMPILE_OPTIONS -fvisibility=default) diff --git a/core/libs/prx/libSceNgs2.native/CMakeLists.txt b/core/libs/prx/libSceNgs2.native/CMakeLists.txt index fddd6277ab..2ebaae1246 100644 --- a/core/libs/prx/libSceNgs2.native/CMakeLists.txt +++ b/core/libs/prx/libSceNgs2.native/CMakeLists.txt @@ -1,5 +1,7 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/Ngs2Library.cmake) add_sce_ngs2_library(libSceNgs2.native) +target_sources(libSceNgs2.native PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/Export.cpp) +set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/Export.cpp PROPERTIES COMPILE_OPTIONS -fvisibility=default) if(BUILD_TESTING) foreach(ngs2Test IN ITEMS Render Atrac9 Filter Custom Parse Stream UserFx Report Geom VoiceIndex HandleErrors VoiceHandles VoiceEvents) diff --git a/core/libs/prx/libSceNgs2.native/tests/Ngs2HandleErrors.cpp b/core/libs/prx/libSceNgs2.native/tests/Ngs2HandleErrors.cpp index 9682af0e24..27f5dbc9f6 100644 --- a/core/libs/prx/libSceNgs2.native/tests/Ngs2HandleErrors.cpp +++ b/core/libs/prx/libSceNgs2.native/tests/Ngs2HandleErrors.cpp @@ -1,4 +1,5 @@ #include "Ngs2Test.hpp" +#include "prx/libSceNgs2.native/include/Api.hpp" #include #include @@ -13,6 +14,16 @@ static void Status(int actual, int expected, const char* message) { if (actual != expected) throw std::runtime_error(message); } +static void CheckUnimplemented() { + try { + sceNgs2RackQueryInfo(); + } catch (const std::runtime_error& error) { + Require(std::string(error.what()) == "sceNgs2RackQueryInfo not implemented"); + return; + } + throw std::runtime_error("sceNgs2RackQueryInfo must report that it is not implemented"); +} + static void CheckResetOption() { Status(sceNgs2SystemResetOption(nullptr), static_cast(0x804A8010u), "null system option did not return the invalid out address error"); constexpr std::uint64_t size = 0x90; @@ -316,6 +327,7 @@ int main() { CheckSystemOption(); CheckSetGrainSamples(); CheckSetSampleRate(); + CheckUnimplemented(); std::cout << "NGS2 PS5 handle errors and validation precedence checked\n"; return 0; } catch (const std::exception& error) { diff --git a/core/libs/prx/libSceNgs2/CMakeLists.txt b/core/libs/prx/libSceNgs2/CMakeLists.txt index 41b6cfe96a..4317aefe6a 100644 --- a/core/libs/prx/libSceNgs2/CMakeLists.txt +++ b/core/libs/prx/libSceNgs2/CMakeLists.txt @@ -1,6 +1,7 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/../libSceNgs2.native/Ngs2Library.cmake) add_sce_ngs2_library(libSceNgs2) target_sources(libSceNgs2 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/PendingExports.cpp) +set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/PendingExports.cpp PROPERTIES COMPILE_OPTIONS -fvisibility=default) if(BUILD_TESTING) add_test_executable(ngs2_core_render_tests ${CMAKE_CURRENT_SOURCE_DIR}/../libSceNgs2.native/tests/Ngs2Render.cpp) diff --git a/core/libs/prx/libSceNpTrophy2/CMakeLists.txt b/core/libs/prx/libSceNpTrophy2/CMakeLists.txt index a7189fbc13..7f9d3efe3a 100644 --- a/core/libs/prx/libSceNpTrophy2/CMakeLists.txt +++ b/core/libs/prx/libSceNpTrophy2/CMakeLists.txt @@ -1,4 +1,5 @@ add_library(libSceNpTrophy2 SHARED EXCLUDE_FROM_ALL + ${CMAKE_CURRENT_SOURCE_DIR}/Export.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Context.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Handle.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/GameInfo.cpp diff --git a/core/libs/prx/libSceNpUniversalDataSystem/CMakeLists.txt b/core/libs/prx/libSceNpUniversalDataSystem/CMakeLists.txt index 62016d6a55..9d02b23500 100644 --- a/core/libs/prx/libSceNpUniversalDataSystem/CMakeLists.txt +++ b/core/libs/prx/libSceNpUniversalDataSystem/CMakeLists.txt @@ -1,4 +1,5 @@ add_library(libSceNpUniversalDataSystem SHARED EXCLUDE_FROM_ALL + ${CMAKE_CURRENT_SOURCE_DIR}/Export.cpp ${CMAKE_CURRENT_SOURCE_DIR}/PendingExports.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/System.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Context.cpp diff --git a/core/libs/tests/GuestNpTrophy2.cpp b/core/libs/tests/GuestNpTrophy2.cpp index 2dcaa5f409..2587f00f58 100644 --- a/core/libs/tests/GuestNpTrophy2.cpp +++ b/core/libs/tests/GuestNpTrophy2.cpp @@ -5,6 +5,7 @@ #include #include #include +#include static void Require(bool value) { if (!value) std::abort(); } @@ -29,6 +30,13 @@ int main() { Require(sceNpTrophy2ShowTrophyList(1) == 0); + try { + sceNpTrophy2SystemCreateContext(); + Require(false); + } catch (const std::runtime_error& error) { + Require(std::string(error.what()) == "sceNpTrophy2SystemCreateContext not implemented"); + } + NpTrophy2GameDetails details{}; NpTrophy2GameData data{}; Require(sceNpTrophy2GetGameInfo(1, 1, &details, nullptr) == 0); diff --git a/core/libs/tests/GuestNpTrophyData.cpp b/core/libs/tests/GuestNpTrophyData.cpp index 6810f8a3da..2c1a678be5 100644 --- a/core/libs/tests/GuestNpTrophyData.cpp +++ b/core/libs/tests/GuestNpTrophyData.cpp @@ -223,6 +223,16 @@ static void ReportPlaceholders() { } } +static void ReportUnimplemented() { + try { + sceNpUniversalDataSystemIntInitialize(); + } catch (const std::runtime_error& error) { + Require(std::string(error.what()) == "sceNpUniversalDataSystemIntInitialize not implemented", "sceNpUniversalDataSystemIntInitialize threw"); + return; + } + Require(false, "sceNpUniversalDataSystemIntInitialize must report that it is not implemented"); +} + int main() { const auto previous = std::filesystem::current_path(); const auto root = std::filesystem::temp_directory_path() / ("anyps5-trophy-data-" + std::to_string(std::random_device{}())); @@ -236,6 +246,7 @@ int main() { ReportTrophyData(context); PostUnlocks(context); ReportPlaceholders(); + ReportUnimplemented(); std::filesystem::current_path(previous); std::filesystem::remove_all(root); From a073f12cd06756502a3b700a211ba393b52fddff Mon Sep 17 00:00:00 2001 From: Ahmad Mujahid Date: Mon, 26 Oct 2026 18:34:31 +0400 Subject: [PATCH 2/2] test: check the split-export stubs are linked without calling them --- core/libs/prx/libSceAgc/tests/Platform.cpp | 14 ++++---------- .../tests/UnsupportedDiagnostics.cpp | 11 ++--------- .../libSceNgs2.native/tests/Ngs2HandleErrors.cpp | 13 ++++--------- core/libs/tests/GuestNpTrophy2.cpp | 9 ++------- core/libs/tests/GuestNpTrophyData.cpp | 13 ++++--------- 5 files changed, 16 insertions(+), 44 deletions(-) diff --git a/core/libs/prx/libSceAgc/tests/Platform.cpp b/core/libs/prx/libSceAgc/tests/Platform.cpp index 33fa04b752..dd7104fd07 100644 --- a/core/libs/prx/libSceAgc/tests/Platform.cpp +++ b/core/libs/prx/libSceAgc/tests/Platform.cpp @@ -6,7 +6,6 @@ #include #include #include -#include namespace { @@ -36,14 +35,9 @@ void testRejections() { expectFailure([] { sceAgcGetIsTrinityMode(nullptr); }); } -void testUnimplemented() { - try { - sceAgcSuspendPointAndCheckStatus(); - } catch (const std::runtime_error& error) { - check(std::string(error.what()) == "sceAgcSuspendPointAndCheckStatus not implemented", "sceAgcSuspendPointAndCheckStatus threw"); - return; - } - throw std::runtime_error("sceAgcSuspendPointAndCheckStatus must report that it is not implemented"); +void testExportLinked() { + auto* volatile linked = &sceAgcSuspendPointAndCheckStatus; + check(linked != nullptr, "sceAgcSuspendPointAndCheckStatus is not linked"); } } @@ -52,7 +46,7 @@ int main() { try { testTrinityMode(); testRejections(); - testUnimplemented(); + testExportLinked(); LibcRunShutdown_nid_postfix(); std::puts("AGC platform tests passed"); return 0; diff --git a/core/libs/prx/libSceAgcDriver/tests/UnsupportedDiagnostics.cpp b/core/libs/prx/libSceAgcDriver/tests/UnsupportedDiagnostics.cpp index 00df156cf9..85a226d1bf 100644 --- a/core/libs/prx/libSceAgcDriver/tests/UnsupportedDiagnostics.cpp +++ b/core/libs/prx/libSceAgcDriver/tests/UnsupportedDiagnostics.cpp @@ -1,17 +1,10 @@ #include "prx/libSceAgcDriver/include/AgcDriver.hpp" #include "SceTypes.hpp" -#include -#include - int main() { if (sceAgcDriverGetCoredumpAddress() != nullptr) return 1; if (sceAgcDriverSetTargetRingForDiag() != static_cast(0x8A6D0001)) return 2; - try { - sceAgcDriverSetFlip(); - return 3; - } catch (const std::runtime_error& error) { - if (std::string(error.what()) != "sceAgcDriverSetFlip not implemented") return 4; - } + auto* volatile linked = &sceAgcDriverSetFlip; + if (linked == nullptr) return 3; return 0; } diff --git a/core/libs/prx/libSceNgs2.native/tests/Ngs2HandleErrors.cpp b/core/libs/prx/libSceNgs2.native/tests/Ngs2HandleErrors.cpp index 27f5dbc9f6..817367de68 100644 --- a/core/libs/prx/libSceNgs2.native/tests/Ngs2HandleErrors.cpp +++ b/core/libs/prx/libSceNgs2.native/tests/Ngs2HandleErrors.cpp @@ -14,14 +14,9 @@ static void Status(int actual, int expected, const char* message) { if (actual != expected) throw std::runtime_error(message); } -static void CheckUnimplemented() { - try { - sceNgs2RackQueryInfo(); - } catch (const std::runtime_error& error) { - Require(std::string(error.what()) == "sceNgs2RackQueryInfo not implemented"); - return; - } - throw std::runtime_error("sceNgs2RackQueryInfo must report that it is not implemented"); +static void CheckExportLinked() { + auto* volatile linked = &sceNgs2RackQueryInfo; + Require(linked != nullptr); } static void CheckResetOption() { @@ -327,7 +322,7 @@ int main() { CheckSystemOption(); CheckSetGrainSamples(); CheckSetSampleRate(); - CheckUnimplemented(); + CheckExportLinked(); std::cout << "NGS2 PS5 handle errors and validation precedence checked\n"; return 0; } catch (const std::exception& error) { diff --git a/core/libs/tests/GuestNpTrophy2.cpp b/core/libs/tests/GuestNpTrophy2.cpp index 2587f00f58..3468d57230 100644 --- a/core/libs/tests/GuestNpTrophy2.cpp +++ b/core/libs/tests/GuestNpTrophy2.cpp @@ -5,7 +5,6 @@ #include #include #include -#include static void Require(bool value) { if (!value) std::abort(); } @@ -30,12 +29,8 @@ int main() { Require(sceNpTrophy2ShowTrophyList(1) == 0); - try { - sceNpTrophy2SystemCreateContext(); - Require(false); - } catch (const std::runtime_error& error) { - Require(std::string(error.what()) == "sceNpTrophy2SystemCreateContext not implemented"); - } + auto* volatile linked = &sceNpTrophy2SystemCreateContext; + Require(linked != nullptr); NpTrophy2GameDetails details{}; NpTrophy2GameData data{}; diff --git a/core/libs/tests/GuestNpTrophyData.cpp b/core/libs/tests/GuestNpTrophyData.cpp index 2c1a678be5..71275707f9 100644 --- a/core/libs/tests/GuestNpTrophyData.cpp +++ b/core/libs/tests/GuestNpTrophyData.cpp @@ -223,14 +223,9 @@ static void ReportPlaceholders() { } } -static void ReportUnimplemented() { - try { - sceNpUniversalDataSystemIntInitialize(); - } catch (const std::runtime_error& error) { - Require(std::string(error.what()) == "sceNpUniversalDataSystemIntInitialize not implemented", "sceNpUniversalDataSystemIntInitialize threw"); - return; - } - Require(false, "sceNpUniversalDataSystemIntInitialize must report that it is not implemented"); +static void ReportExportLinked() { + auto* volatile linked = &sceNpUniversalDataSystemIntInitialize; + Require(linked != nullptr, "sceNpUniversalDataSystemIntInitialize is not linked"); } int main() { @@ -246,7 +241,7 @@ int main() { ReportTrophyData(context); PostUnlocks(context); ReportPlaceholders(); - ReportUnimplemented(); + ReportExportLinked(); std::filesystem::current_path(previous); std::filesystem::remove_all(root);