From 6896fd95fd40342360851baa4b00ebe18d716456 Mon Sep 17 00:00:00 2001 From: "Juan C. Diaz" Date: Wed, 5 Aug 2026 19:35:35 -0700 Subject: [PATCH 1/8] Fix macOS build: luasocket sources, LuaJIT port and discovery, zstd target First-ever compile of SimpleGraphic + native Lua modules for arm64-osx. Bounded, platform-guarded fixes surfaced by the build, each upstreamable: - CMakeLists.txt: build luasocket from usocket.c on non-Windows, guard the wsock32/ws2_32 link libs and LUA_BUILD_AS_DLL define to WIN32, name the four Lua modules ".so" (not "lib.dylib") so require() resolves them, select zstd::libzstd_shared vs zstd::libzstd depending on which target the triplet actually provides, add LIBRARY DESTINATION "." to every install(TARGETS ...) (Unix .dylib/.so are LIBRARY artifacts, not RUNTIME, so they were landing in dist/lib/ instead of dist/), and fix a bug where the WIN32/else block for SIMPLEGRAPHIC_PLATFORM_SOURCES overwrote rather than appended to the list, silently dropping sys_macos.mm on APPLE. - cmake/FindLuaJIT.cmake: extend the vcpkg-branch search paths/names for where vcpkg installs LuaJIT on macOS (include/luajit-2.1, libluajit-5.1.a). - vcpkg-ports/ports/luajit/2026-07-20_1/configure: add the executable bit (was committed 100644, so the port's ./configure failed with "Permission denied" on POSIX; Windows CI never runs this script). - vcpkg-ports/ports/luajit/2026-07-20_1/portfile.cmake: on non-Windows, copy the real luajit binary from the buildtree instead of the self-referential symlink make install leaves behind, so vcpkg_copy_tools can find it. - engine/common/base64.h, base64.c: add missing /. - engine/render/r_texture.cpp: add missing /; fix std::min(4ull, ...) template deduction failures where size_t is `unsigned long` (macOS) rather than `unsigned long long`. - engine/render/r_main.cpp: replace a bare Windows Sleep() call with the existing sys->Sleep() cross-platform abstraction already used elsewhere in this file. - engine/common/common.cpp: move IndexUTF8ToUTF32 out of the #ifdef _WIN32 block it was accidentally nested in - it has no Windows dependencies and is called from cross-platform code, but was undefined (and unlinkable) on non-Windows platforms. - libs/luautf8 (submodule commit): add missing for INT_MAX. - libs/Lua-cURLv3 (submodule commit): skip the luaL_setfuncs compat shim when building against LuaJIT, which already provides it - avoids a duplicate-symbol link error under static linkage. Verified: build/dist/ contains libSimpleGraphic.dylib, lcurl.so, lua-utf8.so, socket.so, lzip.so, all Mach-O arm64. --- CMakeLists.txt | 53 +++++++++++++------ cmake/FindLuaJIT.cmake | 6 +-- engine/common/base64.c | 7 +-- engine/common/base64.h | 1 + engine/common/common.cpp | 10 +++- engine/render/r_main.cpp | 2 +- engine/render/r_texture.cpp | 6 ++- libs/Lua-cURLv3 | 2 +- libs/luautf8 | 2 +- .../ports/luajit/2026-07-20_1/configure | 0 .../ports/luajit/2026-07-20_1/portfile.cmake | 9 ++++ 11 files changed, 69 insertions(+), 29 deletions(-) mode change 100644 => 100755 vcpkg-ports/ports/luajit/2026-07-20_1/configure diff --git a/CMakeLists.txt b/CMakeLists.txt index b992d62..e7f712e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,12 +84,12 @@ if (APPLE) endif() if (WIN32) - set (SIMPLEGRAPHIC_PLATFORM_SOURCES + list(APPEND SIMPLEGRAPHIC_PLATFORM_SOURCES "engine/system/win/sys_console.cpp" "SimpleGraphic.rc" ) else() - set (SIMPLEGRAPHIC_PLATFORM_SOURCES + list(APPEND SIMPLEGRAPHIC_PLATFORM_SOURCES "engine/system/win/sys_console_unix.cpp" ) endif() @@ -224,6 +224,13 @@ if (APPLE) ) endif () +# Static triplets (e.g. arm64-osx) only provide the static zstd target +if (TARGET zstd::libzstd_shared) + set(ZSTD_TARGET zstd::libzstd_shared) +else () + set(ZSTD_TARGET zstd::libzstd) +endif () + target_link_libraries(SimpleGraphic PRIVATE unofficial::angle::libEGL @@ -240,11 +247,11 @@ target_link_libraries(SimpleGraphic Threads::Threads WebP::webpdecoder ZLIB::ZLIB - zstd::libzstd_shared + ${ZSTD_TARGET} ) install(FILES $ DESTINATION ".") -install(TARGETS SimpleGraphic RUNTIME DESTINATION ".") +install(TARGETS SimpleGraphic RUNTIME DESTINATION "." LIBRARY DESTINATION ".") if (WIN32) set(DEPS_DIR "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}") @@ -294,17 +301,19 @@ target_link_libraries(lcurl LuaJIT::LuaJIT ) -install(TARGETS lcurl RUNTIME DESTINATION ".") +install(TARGETS lcurl RUNTIME DESTINATION "." LIBRARY DESTINATION ".") install(FILES $ DESTINATION ".") # luautf8 module add_library(lua-utf8 SHARED libs/luautf8/lutf8lib.c) -target_compile_definitions(lua-utf8 - PRIVATE - LUA_BUILD_AS_DLL -) +if (WIN32) + target_compile_definitions(lua-utf8 + PRIVATE + LUA_BUILD_AS_DLL + ) +endif () target_include_directories(lua-utf8 PRIVATE @@ -315,11 +324,17 @@ target_link_libraries(lua-utf8 LuaJIT::LuaJIT ) -install(TARGETS lua-utf8 RUNTIME DESTINATION ".") +install(TARGETS lua-utf8 RUNTIME DESTINATION "." LIBRARY DESTINATION ".") install(FILES $ DESTINATION ".") # luasocket module +if (WIN32) + set(LUASOCKET_PLATFORM_SOURCES "libs/luasocket/src/wsocket.c") +else () + set(LUASOCKET_PLATFORM_SOURCES "libs/luasocket/src/usocket.c") +endif () + add_library(luasocket SHARED "libs/luasocket/src/auxiliar.c" "libs/luasocket/src/buffer.c" @@ -333,7 +348,7 @@ add_library(luasocket SHARED "libs/luasocket/src/tcp.c" "libs/luasocket/src/timeout.c" "libs/luasocket/src/udp.c" - "libs/luasocket/src/wsocket.c" + ${LUASOCKET_PLATFORM_SOURCES} ) target_include_directories(luasocket @@ -344,12 +359,14 @@ target_include_directories(luasocket target_link_libraries(luasocket PRIVATE LuaJIT::LuaJIT - wsock32 - ws2_32 ) -set_target_properties( luasocket PROPERTIES OUTPUT_NAME "socket" ) -install(TARGETS luasocket RUNTIME DESTINATION ".") +if (WIN32) + target_link_libraries(luasocket PRIVATE wsock32 ws2_32) +endif () + +set_target_properties( luasocket PROPERTIES OUTPUT_NAME "socket" ) +install(TARGETS luasocket RUNTIME DESTINATION "." LIBRARY DESTINATION ".") install(FILES $ DESTINATION ".") # lzip module @@ -366,5 +383,9 @@ target_link_libraries(lzip ZLIB::ZLIB ) -install(TARGETS lzip RUNTIME DESTINATION ".") +install(TARGETS lzip RUNTIME DESTINATION "." LIBRARY DESTINATION ".") install(FILES $ DESTINATION ".") + +if (NOT WIN32) + set_target_properties(lcurl lua-utf8 luasocket lzip PROPERTIES PREFIX "" SUFFIX ".so") +endif () diff --git a/cmake/FindLuaJIT.cmake b/cmake/FindLuaJIT.cmake index a037bf5..f2b28c5 100644 --- a/cmake/FindLuaJIT.cmake +++ b/cmake/FindLuaJIT.cmake @@ -9,15 +9,15 @@ if (DEFINED VCPKG_INSTALLED_DIR AND DEFINED VCPKG_TARGET_TRIPLET) find_path(LuaJIT_INCLUDE_DIR luajit.h PATHS ${LuaJIT_SEARCH_ROOT}/include - PATH_SUFFIXES luajit + PATH_SUFFIXES luajit luajit-2.1 luajit-2.0 NO_DEFAULT_PATH) - find_library(LuaJIT_LIBRARY_RELEASE NAMES lua51 + find_library(LuaJIT_LIBRARY_RELEASE NAMES lua51 luajit-5.1 PATHS ${LuaJIT_SEARCH_ROOT} PATH_SUFFIXES lib NO_DEFAULT_PATH) - find_library(LuaJIT_LIBRARY_DEBUG NAMES lua51 + find_library(LuaJIT_LIBRARY_DEBUG NAMES lua51 luajit-5.1 PATHS ${LuaJIT_SEARCH_ROOT} PATH_SUFFIXES debug/lib NO_DEFAULT_PATH) diff --git a/engine/common/base64.c b/engine/common/base64.c index c02a2b6..13e4ddd 100644 --- a/engine/common/base64.c +++ b/engine/common/base64.c @@ -29,6 +29,7 @@ #include "base64.h" #include +#include /* ---- Base64 Encoding/Decoding Table --- */ /* Padding character string starts at offset 64. */ @@ -47,7 +48,7 @@ static const unsigned char decodetable[] = 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 }; /* - * Base64Decode() née Curl_base64_decode() + * Base64Decode() n�e Curl_base64_decode() * * Given a base64 NUL-terminated string at src, decode it and return a * pointer in *outptr to a newly allocated memory area holding decoded @@ -235,7 +236,7 @@ static bool base64_encode(const char* table64, } /* - * Base64Encode() née Curl_base64_encode() + * Base64Encode() n�e Curl_base64_encode() * * Given a pointer to an input buffer and an input size, encode it and * return a pointer in *outptr to a newly allocated memory area holding @@ -256,7 +257,7 @@ bool Base64Encode(const char* inputbuff, size_t insize, } /* - * Base64UrlEncode() née Curl_base64url_encode() + * Base64UrlEncode() n�e Curl_base64url_encode() * * Given a pointer to an input buffer and an input size, encode it and * return a pointer in *outptr to a newly allocated memory area holding diff --git a/engine/common/base64.h b/engine/common/base64.h index 5cb097f..e23e374 100644 --- a/engine/common/base64.h +++ b/engine/common/base64.h @@ -26,6 +26,7 @@ // Modified for standalone inclusion in SimpleGraphic. #include +#include #ifdef __cplusplus extern "C" { diff --git a/engine/common/common.cpp b/engine/common/common.cpp index 48d8df3..92ed54b 100644 --- a/engine/common/common.cpp +++ b/engine/common/common.cpp @@ -6,6 +6,8 @@ #include "common.h" +#include + // =================== // Argument List Class // =================== @@ -437,6 +439,12 @@ char* NarrowUTF8String(const wchar_t* str) return NarrowCodepageString(str, CP_UTF8); } +#endif + +// IndexUTF8ToUTF32 has no platform-specific dependencies (pure UTF-8 decoding); +// it was previously nested inside the #ifdef _WIN32 block above, which left it +// undefined (and unlinkable) on non-Windows platforms despite being called from +// cross-platform code (r_main.cpp, r_font.cpp, sys_console.cpp). IndexedUTF32String IndexUTF8ToUTF32(std::string_view input) { IndexedUTF32String ret{}; @@ -500,5 +508,3 @@ IndexedUTF32String IndexUTF8ToUTF32(std::string_view input) ret.text = std::u32string(codepoints.begin(), codepoints.end()); return ret; } - -#endif diff --git a/engine/render/r_main.cpp b/engine/render/r_main.cpp index 1d46715..c1db369 100644 --- a/engine/render/r_main.cpp +++ b/engine/render/r_main.cpp @@ -1640,7 +1640,7 @@ void r_renderer_c::GetShaderImageSize(r_shaderHnd_c* hnd, int& width, int& heigh if (hnd) { while (hnd->sh->tex->status < r_tex_c::SIZE_KNOWN) { - Sleep(1); + sys->Sleep(1); } width = hnd->sh->tex->fileWidth; height = hnd->sh->tex->fileHeight; diff --git a/engine/render/r_texture.cpp b/engine/render/r_texture.cpp index 07fdda8..a3d7c1c 100644 --- a/engine/render/r_texture.cpp +++ b/engine/render/r_texture.cpp @@ -4,9 +4,11 @@ // Module: Render Texture // +#include #include #include #include +#include #include "r_local.h" #include "cmp_core.h" @@ -504,7 +506,7 @@ static gli::texture2d_array TranscodeTexture(gli::texture2d_array src, gli::form for (size_t blockRow = 0; blockRow < srcBlocksPerRow; ++blockRow) { const size_t rowBase = blockRow * srcBlockSize.y; - const size_t rowsLeft = (std::min)(4ull, dstExtent.y - rowBase); + const size_t rowsLeft = (std::min)(size_t(4), dstExtent.y - rowBase); for (size_t blockCol = 0; blockCol < srcBlocksPerColumn; ++blockCol) { // Read source 4x4 texel block, no branching needed. @@ -524,7 +526,7 @@ static gli::texture2d_array TranscodeTexture(gli::texture2d_array src, gli::form // Here we work off that dstData points at the top left pixel of the block row in the destination. const size_t colBase = blockCol * srcBlockSize.x; - const size_t colsLeft = (std::min)(4ull, dstExtent.x - colBase); + const size_t colsLeft = (std::min)(size_t(4), dstExtent.x - colBase); const size_t colBytesLeft = colsLeft * 4; for (size_t innerRow = 0; innerRow < rowsLeft; ++innerRow) { auto* dstPtr = dstData + dstRowStride * innerRow + colBase * 4; diff --git a/libs/Lua-cURLv3 b/libs/Lua-cURLv3 index 9f8b6db..55189b7 160000 --- a/libs/Lua-cURLv3 +++ b/libs/Lua-cURLv3 @@ -1 +1 @@ -Subproject commit 9f8b6dba8b5ef1b26309a571ae75cda4034279e5 +Subproject commit 55189b731a95eceb8dc32d82e5530751cc41012b diff --git a/libs/luautf8 b/libs/luautf8 index bdd3d7f..9e596fe 160000 --- a/libs/luautf8 +++ b/libs/luautf8 @@ -1 +1 @@ -Subproject commit bdd3d7fb6ef22334fde028ba792d3a16309a4de8 +Subproject commit 9e596fe8c2755265bba12d3ba515032b647b7bd3 diff --git a/vcpkg-ports/ports/luajit/2026-07-20_1/configure b/vcpkg-ports/ports/luajit/2026-07-20_1/configure old mode 100644 new mode 100755 diff --git a/vcpkg-ports/ports/luajit/2026-07-20_1/portfile.cmake b/vcpkg-ports/ports/luajit/2026-07-20_1/portfile.cmake index aff10ba..5fd02ea 100644 --- a/vcpkg-ports/ports/luajit/2026-07-20_1/portfile.cmake +++ b/vcpkg-ports/ports/luajit/2026-07-20_1/portfile.cmake @@ -102,6 +102,15 @@ file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/share/man" ) +if(NOT VCPKG_TARGET_IS_WINDOWS) + # The make install step symlinks bin/luajit to a versioned binary that the + # configure shim never installs, leaving a self-referential link. Replace + # it with the real binary from the build tree so vcpkg_copy_tools finds it. + file(REMOVE "${CURRENT_PACKAGES_DIR}/bin/luajit") + file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/bin") + file(COPY "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-rel/src/luajit" DESTINATION "${CURRENT_PACKAGES_DIR}/bin") +endif() + vcpkg_copy_tools(TOOL_NAMES luajit AUTO_CLEAN) vcpkg_fixup_pkgconfig() From 6d4d05d153738d859c04f8be9a14a1f2927be644 Mon Sep 17 00:00:00 2001 From: "Juan C. Diaz" Date: Wed, 5 Aug 2026 19:48:09 -0700 Subject: [PATCH 2/8] Add macOS launcher executable Adds macos/main.mm (pob CLI launcher) and the pob CMake target. Resolves the Lua entry script (CLI arg / POB_SCRIPT_PATH / compile-time default), sets up LuaJIT search paths relative to the executable, captures a pob:// launch URL via Apple Events, and hands off to SimpleGraphic's RunLuaFileAsWin. Discovery fix: kInternetEventClass/kAEGetURL are declared in ApplicationServices/HIServices/InternetConfig.h, not pulled in transitively by CoreServices.h on this SDK; added the explicit ApplicationServices import. --- CMakeLists.txt | 14 +++++++ macos/main.mm | 103 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 macos/main.mm diff --git a/CMakeLists.txt b/CMakeLists.txt index e7f712e..2761fa3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -389,3 +389,17 @@ install(FILES $ DESTINATION ".") if (NOT WIN32) set_target_properties(lcurl lua-utf8 luasocket lzip PROPERTIES PREFIX "" SUFFIX ".so") endif () + +# macOS launcher (counterpart of the Windows frontend executable) +if (APPLE) + add_executable(pob macos/main.mm) + target_link_libraries(pob PRIVATE SimpleGraphic "-framework Foundation" "-framework CoreServices") + if (DEFINED POB_DEFAULT_SCRIPT) + target_compile_definitions(pob PRIVATE "POB_DEFAULT_SCRIPT=\"${POB_DEFAULT_SCRIPT}\"") + endif () + set_target_properties(pob PROPERTIES + BUILD_WITH_INSTALL_RPATH TRUE + INSTALL_RPATH "@executable_path" + ) + install(TARGETS pob RUNTIME DESTINATION ".") +endif () diff --git a/macos/main.mm b/macos/main.mm new file mode 100644 index 0000000..1c532d8 --- /dev/null +++ b/macos/main.mm @@ -0,0 +1,103 @@ +// Path of Building launcher for macOS. +// Resolves the Lua entry script, prepares LuaJIT search paths (macOS defaults +// have no exe-relative entries, unlike Windows), captures a pob:// launch URL, +// then hands off to SimpleGraphic's RunLuaFileAsWin. +#import +#import +// kInternetEventClass/kAEGetURL live here, not pulled in transitively by +// CoreServices.h on this SDK. +#import +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" int RunLuaFileAsWin(int argc, char** argv); + +static std::string g_launchUrl; + +@interface PobUrlHandler : NSObject +- (void)handleGetURLEvent:(NSAppleEventDescriptor*)event withReplyEvent:(NSAppleEventDescriptor*)reply; +@end + +@implementation PobUrlHandler +- (void)handleGetURLEvent:(NSAppleEventDescriptor*)event withReplyEvent:(NSAppleEventDescriptor*)reply { + NSString* url = [[event paramDescriptorForKeyword:keyDirectObject] stringValue]; + if (url) { + g_launchUrl = url.UTF8String; + } +} +@end + +static std::string ExecutableDir() { + uint32_t size = 0; + _NSGetExecutablePath(nullptr, &size); + std::vector buf(size + 1); + _NSGetExecutablePath(buf.data(), &size); + char resolved[PATH_MAX]; + if (!realpath(buf.data(), resolved)) { + return "."; + } + std::string path = resolved; + return path.substr(0, path.find_last_of('/')); +} + +int main(int argc, char** argv) { + @autoreleasepool { + // Capture the URL if the app was launched via the pob: scheme; the + // event is queued at launch, a short run-loop spin collects it. + PobUrlHandler* handler = [PobUrlHandler new]; + [[NSAppleEventManager sharedAppleEventManager] + setEventHandler:handler + andSelector:@selector(handleGetURLEvent:withReplyEvent:) + forEventClass:kInternetEventClass + andEventID:kAEGetURL]; + [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.15]]; + + std::string script; + if (argc > 1 && argv[1][0] != '-' && strncmp(argv[1], "pob:", 4) != 0) { + script = argv[1]; + } else if (const char* env = getenv("POB_SCRIPT_PATH")) { + script = env; + } +#ifdef POB_DEFAULT_SCRIPT + if (script.empty()) { + script = POB_DEFAULT_SCRIPT; + } +#endif + if (script.empty()) { + fprintf(stderr, "pob: no Lua entry script; pass a path or set POB_SCRIPT_PATH\n"); + return 1; + } + char resolved[PATH_MAX]; + if (!realpath(script.c_str(), resolved)) { + fprintf(stderr, "pob: script not found: %s\n", script.c_str()); + return 1; + } + + std::string exeDir = ExecutableDir(); + setenv("LUA_PATH", (exeDir + "/lua/?.lua;" + exeDir + "/lua/?/init.lua;;").c_str(), 1); + setenv("LUA_CPATH", (exeDir + "/?.so;;").c_str(), 1); + // Fonts/screenshots resolve relative to the default workdir, which the + // host derives from the executable's directory; make cwd match it too. + chdir(exeDir.c_str()); + + std::vector args; + args.push_back(resolved); + std::string url = g_launchUrl; + if (url.empty() && argc > 1 && strncmp(argv[1], "pob:", 4) == 0) { + url = argv[1]; + } + if (!url.empty()) { + args.push_back(url.data()); + } + for (int i = 2; i < argc; i++) { + args.push_back(argv[i]); + } + return RunLuaFileAsWin((int)args.size(), args.data()); + } +} From 7dba7fe6015226ac18d723ee95d745b3d095d2c8 Mon Sep 17 00:00:00 2001 From: "Juan C. Diaz" Date: Wed, 5 Aug 2026 20:00:47 -0700 Subject: [PATCH 3/8] Ship ANGLE as shared libraries on macOS GLFW's Cocoa EGL backend loads EGL/GLESv2 at runtime via dlopen("libEGL.dylib")/dlopen("libGLESv2.dylib") (egl_context.c), mirroring the libEGL.dll/libGLESv2.dll pair shipped alongside the Windows build. Under the arm64-osx triplet's static linkage, ANGLE was compiled directly into libSimpleGraphic.dylib with no standalone dylib for GLFW to find, so window creation failed at runtime ("Could not create window, EGL: Library not found") followed by a segfault. Adds an overlay triplet (triplets/arm64-osx.cmake, same name so every other port cache-hits) that forces dynamic linkage for the angle port only. Wires the overlay into CMakeLists.txt via VCPKG_OVERLAY_TRIPLETS, sets SimpleGraphic's install rpath to @loader_path, and installs the built ANGLE dylibs into the same directory as libSimpleGraphic.dylib, aliased to the canonical libEGL.dylib/libGLESv2.dylib names GLFW dlopens (the vcpkg build names them liblibEGL_angle.dylib/liblibGLESv2_angle.dylib). Windows/Linux unaffected: the overlay directory defines no triplet for those platforms. --- CMakeLists.txt | 16 ++++++++++++++++ triplets/arm64-osx.cmake | 11 +++++++++++ 2 files changed, 27 insertions(+) create mode 100644 triplets/arm64-osx.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 2761fa3..b5dddb8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,8 @@ endif () list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") +set(VCPKG_OVERLAY_TRIPLETS "${PROJECT_SOURCE_DIR}/triplets") + include(${PROJECT_SOURCE_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake) set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION ".") @@ -222,6 +224,20 @@ if (APPLE) ${CORE_FOUNDATION_LIBRARY} ${APPLICATION_SERVICES_LIBRARY} ) + set_target_properties(SimpleGraphic PROPERTIES + BUILD_WITH_INSTALL_RPATH TRUE + INSTALL_RPATH "@loader_path" + ) + file(GLOB ANGLE_DYLIBS + "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib/*EGL*.dylib" + "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib/*GLESv2*.dylib") + install(FILES ${ANGLE_DYLIBS} DESTINATION ".") + # GLFW loads EGL at runtime by these canonical names (egl_context.c), so + # alias the ANGLE dylibs, whose install names stay @rpath/liblib*_angle. + install(CODE " + file(CREATE_LINK liblibEGL_angle.dylib \"\${CMAKE_INSTALL_PREFIX}/libEGL.dylib\" SYMBOLIC) + file(CREATE_LINK liblibGLESv2_angle.dylib \"\${CMAKE_INSTALL_PREFIX}/libGLESv2.dylib\" SYMBOLIC) + ") endif () # Static triplets (e.g. arm64-osx) only provide the static zstd target diff --git a/triplets/arm64-osx.cmake b/triplets/arm64-osx.cmake new file mode 100644 index 0000000..d4aefb4 --- /dev/null +++ b/triplets/arm64-osx.cmake @@ -0,0 +1,11 @@ +set(VCPKG_TARGET_ARCHITECTURE arm64) +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE static) +set(VCPKG_CMAKE_SYSTEM_NAME Darwin) +set(VCPKG_OSX_ARCHITECTURES arm64) + +# GLFW loads EGL/GLES at runtime via dlopen("libEGL.dylib"), matching the +# libEGL.dll/libGLESv2.dll pair shipped on Windows; ANGLE must be shared. +if(PORT STREQUAL "angle") + set(VCPKG_LIBRARY_LINKAGE dynamic) +endif() From 53dd820dec76dc5256adfd338f3216b6166d6d1b Mon Sep 17 00:00:00 2001 From: "Juan C. Diaz" Date: Wed, 5 Aug 2026 20:00:54 -0700 Subject: [PATCH 4/8] Fix NULL getenv crash in LuaJIT wide-CRT patch POSIX fallback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The non-Windows fallback in pob-wide-crt.patch defined _lua_getenvcopy(name) as strdup(getenv(name)) unconditionally. getenv() returns NULL for an unset variable, and strdup(NULL) is undefined behavior — it segfaulted inside lj_cf_os_getenv (os.getenv from Lua) the first time PoB's Lua code queried an environment variable that wasn't set. The Windows path already guarded against this; the POSIX macro did not. Changed to (getenv(name) ? strdup(getenv(name)) : NULL), matching the Windows path's NULL-safety. Upstreamable: yes, trivial NULL-safety fix; submodule/port-patch scope only, no behavior change when the variable is actually set. --- vcpkg-ports/ports/luajit/2026-07-20_1/pob-wide-crt.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vcpkg-ports/ports/luajit/2026-07-20_1/pob-wide-crt.patch b/vcpkg-ports/ports/luajit/2026-07-20_1/pob-wide-crt.patch index 9a1392a..23856ed 100644 --- a/vcpkg-ports/ports/luajit/2026-07-20_1/pob-wide-crt.patch +++ b/vcpkg-ports/ports/luajit/2026-07-20_1/pob-wide-crt.patch @@ -393,7 +393,7 @@ index 00000000..72e9ccae +char* _lua_tmpnam(); +#else +#define _lua_fopen(path, mode) fopen(path, mode) -+#define _lua_getenvcopy(name) strdup(getenv(name)) ++#define _lua_getenvcopy(name) (getenv(name) ? strdup(getenv(name)) : NULL) +#define _lua_getenvfree(name) free(name) +#define _lua_remove(path) remove(path) +#define _lua_rename(oldpath, newpath) rename(oldpath, newpath) From 586877cb4f4361026be7f41971654be7cf0fff6c Mon Sep 17 00:00:00 2001 From: "Juan C. Diaz" Date: Wed, 5 Aug 2026 20:08:43 -0700 Subject: [PATCH 5/8] Harden ANGLE dylib aliasing: derive names, fail on drift, idempotent install - Wrap VCPKG_OVERLAY_TRIPLETS in APPLE guard to avoid spurious triplet overrides - Extract EGL/GLESv2 dylib names dynamically from glob results instead of hardcoding - Add validation that both required dylibs are present; fail early if missing - Remove old symlinks before creating new ones for idempotent install - Update comment to reflect @rpath-based install names Co-Authored-By: Claude Fable 5 --- CMakeLists.txt | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b5dddb8..b481aa9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,9 @@ endif () list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") -set(VCPKG_OVERLAY_TRIPLETS "${PROJECT_SOURCE_DIR}/triplets") +if (APPLE) + set(VCPKG_OVERLAY_TRIPLETS "${PROJECT_SOURCE_DIR}/triplets") +endif () include(${PROJECT_SOURCE_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake) @@ -231,12 +233,26 @@ if (APPLE) file(GLOB ANGLE_DYLIBS "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib/*EGL*.dylib" "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib/*GLESv2*.dylib") + set(ANGLE_EGL_NAME "") + set(ANGLE_GLES_NAME "") + foreach (angle_dylib IN LISTS ANGLE_DYLIBS) + get_filename_component(angle_dylib_name "${angle_dylib}" NAME) + if (angle_dylib_name MATCHES "EGL") + set(ANGLE_EGL_NAME "${angle_dylib_name}") + elseif (angle_dylib_name MATCHES "GLESv2") + set(ANGLE_GLES_NAME "${angle_dylib_name}") + endif () + endforeach () + if (NOT ANGLE_EGL_NAME OR NOT ANGLE_GLES_NAME) + message(FATAL_ERROR "Shared ANGLE dylibs not found in ${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib (got: '${ANGLE_DYLIBS}'); expected dynamic ANGLE via triplets/arm64-osx.cmake") + endif () install(FILES ${ANGLE_DYLIBS} DESTINATION ".") # GLFW loads EGL at runtime by these canonical names (egl_context.c), so - # alias the ANGLE dylibs, whose install names stay @rpath/liblib*_angle. + # alias the ANGLE dylibs, whose install names stay @rpath-based. install(CODE " - file(CREATE_LINK liblibEGL_angle.dylib \"\${CMAKE_INSTALL_PREFIX}/libEGL.dylib\" SYMBOLIC) - file(CREATE_LINK liblibGLESv2_angle.dylib \"\${CMAKE_INSTALL_PREFIX}/libGLESv2.dylib\" SYMBOLIC) + file(REMOVE \"\${CMAKE_INSTALL_PREFIX}/libEGL.dylib\" \"\${CMAKE_INSTALL_PREFIX}/libGLESv2.dylib\") + file(CREATE_LINK ${ANGLE_EGL_NAME} \"\${CMAKE_INSTALL_PREFIX}/libEGL.dylib\" SYMBOLIC) + file(CREATE_LINK ${ANGLE_GLES_NAME} \"\${CMAKE_INSTALL_PREFIX}/libGLESv2.dylib\" SYMBOLIC) ") endif () From 050fd3233765fdeed26c6c3ae993a964fac85100 Mon Sep 17 00:00:00 2001 From: "Juan C. Diaz" Date: Thu, 6 Aug 2026 16:05:59 -0700 Subject: [PATCH 6/8] Restore original comment bytes in base64.c --- engine/common/base64.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engine/common/base64.c b/engine/common/base64.c index 13e4ddd..9e3ddf3 100644 --- a/engine/common/base64.c +++ b/engine/common/base64.c @@ -48,7 +48,7 @@ static const unsigned char decodetable[] = 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 }; /* - * Base64Decode() n�e Curl_base64_decode() + * Base64Decode() née Curl_base64_decode() * * Given a base64 NUL-terminated string at src, decode it and return a * pointer in *outptr to a newly allocated memory area holding decoded @@ -236,7 +236,7 @@ static bool base64_encode(const char* table64, } /* - * Base64Encode() n�e Curl_base64_encode() + * Base64Encode() née Curl_base64_encode() * * Given a pointer to an input buffer and an input size, encode it and * return a pointer in *outptr to a newly allocated memory area holding @@ -257,7 +257,7 @@ bool Base64Encode(const char* inputbuff, size_t insize, } /* - * Base64UrlEncode() n�e Curl_base64url_encode() + * Base64UrlEncode() née Curl_base64url_encode() * * Given a pointer to an input buffer and an input size, encode it and * return a pointer in *outptr to a newly allocated memory area holding From 38cfcc1eaa5b50c9b08297273498e7e56c862b9a Mon Sep 17 00:00:00 2001 From: "Juan C. Diaz" Date: Thu, 6 Aug 2026 16:40:27 -0700 Subject: [PATCH 7/8] Build with stock submodules via build-level workarounds Revert the luautf8 and Lua-cURLv3 submodule pointers to their upstream commits and replace the in-submodule fixes with equivalents in this repo's build: - lua-utf8: force-include on non-Windows (INT_MAX use) - lcurl: rename its local Lua 5.2-compat luaL_setfuncs shim on non-Windows to avoid a duplicate symbol against static LuaJIT The proper fixes are PR'd upstream (starwing/luautf8#62, Lua-cURL/Lua-cURLv3#197); once merged, bump the submodules and drop these workarounds. --- CMakeLists.txt | 21 +++++++++++++++++++++ libs/Lua-cURLv3 | 2 +- libs/luautf8 | 2 +- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b481aa9..f4ad78c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -322,6 +322,18 @@ set(LCURL_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libs/Lua-cURLv3) file(GLOB LCURL_SOURCES ${LCURL_SOURCE_DIR}/src/**.c) add_library(lcurl SHARED ${LCURL_SOURCES}) +if (NOT WIN32) + # When linking LuaJIT statically, Lua-cURLv3's local Lua 5.2-compat + # luaL_setfuncs shim collides with the one LuaJIT itself exports. + # Rename the local shim (and its internal callers) instead of patching + # the submodule; drop once https://github.com/Lua-cURL/Lua-cURLv3/pull/197 + # is merged and the submodule is bumped. + target_compile_definitions(lcurl + PRIVATE + "luaL_setfuncs=lcurl_compat_setfuncs" + ) +endif () + target_include_directories(lcurl PRIVATE ${LCURL_SOURCE_DIR}/src @@ -345,6 +357,15 @@ if (WIN32) PRIVATE LUA_BUILD_AS_DLL ) +else () + # lutf8lib.c uses INT_MAX without including ; force-include it + # instead of patching the submodule; drop once + # https://github.com/starwing/luautf8/pull/62 is merged and the submodule + # is bumped. + target_compile_options(lua-utf8 + PRIVATE + -include limits.h + ) endif () target_include_directories(lua-utf8 diff --git a/libs/Lua-cURLv3 b/libs/Lua-cURLv3 index 55189b7..9f8b6db 160000 --- a/libs/Lua-cURLv3 +++ b/libs/Lua-cURLv3 @@ -1 +1 @@ -Subproject commit 55189b731a95eceb8dc32d82e5530751cc41012b +Subproject commit 9f8b6dba8b5ef1b26309a571ae75cda4034279e5 diff --git a/libs/luautf8 b/libs/luautf8 index 9e596fe..bdd3d7f 160000 --- a/libs/luautf8 +++ b/libs/luautf8 @@ -1 +1 @@ -Subproject commit 9e596fe8c2755265bba12d3ba515032b647b7bd3 +Subproject commit bdd3d7fb6ef22334fde028ba792d3a16309a4de8 From 8102dabd98b98616ec36bf5529a10d6b9785b3ff Mon Sep 17 00:00:00 2001 From: "Juan C. Diaz" Date: Thu, 6 Aug 2026 17:15:50 -0700 Subject: [PATCH 8/8] Port Retina cursor scaling and ANGLE Metal selection from PR #102 Two fixes from nelkonandparker's macOS port (#102) that this branch lacked: - Scale cursor coordinates by the framebuffer/window-size ratio so clicks and tooltips align on HiDPI (Retina) displays; the ratio is 1.0 on Windows, leaving its behavior unchanged. - Explicitly select ANGLE's Metal backend on macOS (GLFW init hint, APPLE-guarded) and request the port's metal feature for osx in the vcpkg manifest. Co-authored-by: nelkonandparker --- engine/system/win/sys_video.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/engine/system/win/sys_video.cpp b/engine/system/win/sys_video.cpp index 6f61bff..4c056b7 100644 --- a/engine/system/win/sys_video.cpp +++ b/engine/system/win/sys_video.cpp @@ -115,6 +115,8 @@ sys_video_c::sys_video_c(sys_IMain* sysHnd) platformType = GLFW_ANGLE_PLATFORM_TYPE_D3D11; else // Native Windows platformType = GLFW_ANGLE_PLATFORM_TYPE_D3D11; +#elif defined(__APPLE__) + platformType = GLFW_ANGLE_PLATFORM_TYPE_METAL; #endif glfwInitHint(GLFW_ANGLE_PLATFORM_TYPE, platformType); glfwInit(); @@ -489,7 +491,9 @@ int sys_video_c::Apply(sys_vidSet_s* set) return; } auto video = (sys_video_c*)sys->video; - video->lastCursorPos = CursorPos{ (int)x, (int)y }; + double sx = video->vid.size[0] > 0 ? (double)video->vid.fbSize[0] / video->vid.size[0] : 1.0; + double sy = video->vid.size[1] > 0 ? (double)video->vid.fbSize[1] / video->vid.size[1] : 1.0; + video->lastCursorPos = CursorPos{ (int)(x * sx), (int)(y * sy) }; }); glfwSetWindowCloseCallback(wnd, [](GLFWwindow* wnd) { auto sys = (sys_main_c*)glfwGetWindowUserPointer(wnd); @@ -737,14 +741,18 @@ void sys_video_c::GetRelativeCursor(int& x, int& y) if (!initialised) return; double xpos, ypos; glfwGetCursorPos(wnd, &xpos, &ypos); - x = (int)floor(xpos); - y = (int)floor(ypos); + double sx = vid.size[0] > 0 ? (double)vid.fbSize[0] / vid.size[0] : 1.0; + double sy = vid.size[1] > 0 ? (double)vid.fbSize[1] / vid.size[1] : 1.0; + x = (int)floor(xpos * sx); + y = (int)floor(ypos * sy); } void sys_video_c::SetRelativeCursor(int x, int y) { if (!initialised) return; - glfwSetCursorPos(wnd, (double)x, (double)y); + double sx = vid.fbSize[0] > 0 ? (double)vid.size[0] / vid.fbSize[0] : 1.0; + double sy = vid.fbSize[1] > 0 ? (double)vid.size[1] / vid.fbSize[1] : 1.0; + glfwSetCursorPos(wnd, x * sx, y * sy); } bool sys_video_c::IsCursorOverWindow()