我決定嘗試在 PSP 上使用 Golang,並探索了多種方法,包括移植 Clang、使用 TinyGo 以及使用 GopherJS 將 Golang 編譯為 JavaScript。然後,我在 PSP 自製程式 Discord 上遇到了一位名為 aethiopicuschan 的用戶,他正在使用 WebAssembly 嘗試實現相同的目標。他的範例在 PPSSPP 上有效,但在實際硬體上無效。
無論如何,由於即將到來的考試,我不得不暫停我的專案。但是,幾個月後,我發現一篇文章,aethiopicuschan 成功地將 Golang 編譯為 WASM,並使用 WASM 解釋器在 PSP 上運行它。
他的方法使用了一個名為 Wasm3 的 Wasm 解釋器來運行程式碼,但我知道我可以做得更好。我知道像 Wasm2C 這樣的項目,可以將 Wasm 二進位轉換為 C。
我很興奮,更深入地研究了這個主題,並發現了一篇有關將 WebAssembly 編譯為可移植 C 程式碼的文章。他們使用了一個名為 w2c2 的編譯器,我猜這是續集。
經過幾個小時的修改 CMake,我成功地使用 TinyGo 並針對 WASI 創建了一個工作範例。我還封裝了一個 raylib 函數 InitWindow(順便說一下,psp 有一個 raylib 連接埠),目的是將 raylib-go 綁定移植到這個 WASM-to-C 平台。此範例成功將 C InitWindow 函數綁定到編譯後的 WASM 程式碼。
如您所見,它看起來與任何其他 golang 程式碼
package main import "time" import rl "github.com/gen2brain/raylib-go/raylib" func main() { rl.InitWindow(480, 272, "Psp test") for { time.Sleep(time.Millisecond * 16) } }
但是在 rl 套件中,我們導入了一個 C 函數,我們也給它一個函數簽名。請記住。
package rl //go:wasmimport rl InitWindow func c_InitWindow(width int32, height int32, title string) // InitWindow - Initialize Window and OpenGL Graphics func InitWindow(width int32, height int32, title string) { c_InitWindow(width, height, title) }
讓我們一步一步分解這段程式碼。
#define __GLIBC_USE #include <raylib.h> #include <stdio.h> #include <time.h> #include <pspkernel.h> PSP_MODULE_INFO("WasiExample", 0, 1, 0); PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER); #include "pspdebug.h" #define printf pspDebugScreenPrintf
這裡我們導入編譯後的模組app.h
我們也導入了 w2c2 提供的 wasi「運行時」
// // the compiled wasm -> C code #include "app.h" // // wasi runtime #include "w2c2_base.h" #include "wasi.h" extern wasmMemory* e_memory; // the WASM memory. void trap(Trap trap) { fprintf(stderr, "TRAP: %s\n", trapDescription(trap)); abort(); } wasmMemory* wasiMemory(void* instance) { return app_memory((appInstance*)instance); } extern char** environ;
陷阱函數是樣板,
wasiMemory 函數是我為另一個輔助函數製作的輔助函數
char* getCStringFromMemory(void* memoryptr, U32 offset, U32 length) { wasmMemory* memory = wasiMemory(memoryptr); char* str = (char*)(memory->data + offset); char* result = (char*)malloc( length + 1); // Allocate space for the string + null terminator if (result == NULL) { fprintf(stderr, "Memory allocation failed\n"); return NULL; } // Copy the string from WASI memory to local memory for (U32 i = 0; i < length; ++i) { result[i] = str[i]; } result[length] = '<pre class="brush:php;toolbar:false">void rl__InitWindow( void* memoryptr, U32 width, U32 height, U32 offset, U32 length) { char* title = getCStringFromMemory(memoryptr, offset, length); InitWindow(width, height, title); bool ready = IsWindowReady(); if (ready) { // this will print to the psp screen. printf("Window was created"); } }'; // Null-terminate the string return result; }
這是我們從 golang 程式碼中呼叫的 C 函數,我必須自己定義它。
int main(int argc, char* argv[]) { pspDebugScreenInit(); appInstance i; appInstantiate(&i, NULL); if (!wasiInit(argc, argv, environ)) { fprintf(stderr, "failed to initialize WASI\n"); return 1; } app__start(&i); appFreeInstance(&i); return 0; }
我們正在讀取轉譯的 wasm 傳遞的參數,並將它們傳遞給 raylib。
這是更多的樣板文件,我們所做的就是運行 golang 程式碼的 main 函數,該函數導出為 app_start()
這是 psp 模擬器的螢幕截圖。
但它也適用於原始硬體。
有問題請在留言區留言!
以上是PSP(和其他語言)上的 Golang的詳細內容。更多資訊請關注PHP中文網其他相關文章!