feat: native Linux support#98
Open
velomeister wants to merge 16 commits intoPathOfBuildingCommunity:masterfrom
Open
feat: native Linux support#98velomeister wants to merge 16 commits intoPathOfBuildingCommunity:masterfrom
velomeister wants to merge 16 commits intoPathOfBuildingCommunity:masterfrom
Conversation
GCC 15 enforces stricter implicit inclusion rules. Add missing headers that were previously available transitively: - base64.c: <string.h> for memset/memcpy - base64.h: <stddef.h> for size_t - core_compress.cpp: <cstring> for memcpy - r_font.cpp: <algorithm> for std::find/std::min
4ull (unsigned long long) doesn't match size_t (unsigned long) on Linux,
causing -Werror failures. Replace with size_t{4} to match the type of the
surrounding expression. Also add missing <algorithm> and <thread> includes.
Sleep() is a Windows-only API. Replace with the portable std::this_thread::sleep_for(). Add the required <chrono> and <thread> includes.
The function only uses standard C++ (std::string_view, char32_t, std::vector) and is called from r_font.cpp and r_main.cpp on all platforms. Move it out of the #ifdef _WIN32 block.
Error("Exception: ", e.what()) is missing the %s format specifier,
causing the exception message to be silently dropped.
SpawnProcess: use fork/execvp to launch child processes. PlatformOpenURL: use xdg-open to open URLs in the default browser. Also remove <uuid/uuid.h> (not available on all distros, unused) and add <sstream>/<vector> required by SpawnProcess.
On Windows the launcher exe lives in runtime/ so basePath resolves correctly. On Linux the binary is in the build dir, so we allow the launcher to set SG_BASE_PATH to point FindBasePath() at the correct runtime data directory (fonts, config, etc.).
- cmp_core, imgui: enable POSITION_INDEPENDENT_CODE (required when linking static libs into a shared library) - SimpleGraphic: suppress -Wno-template-body for sol2/GCC 15 issue - zstd: fall back to static target when shared is unavailable - lcurl: remove lib prefix on Linux; add -Wl,--allow-multiple-definition to resolve luaL_setfuncs symbol collision between LuaJIT and l52util - lua-utf8: remove lib prefix on Linux; use -include limits.h instead of LUA_BUILD_AS_DLL (which is MSVC-specific) - luasocket: switch from wsocket.c to usocket.c on Linux; remove lib prefix; move Windows-only wsock32/ws2_32 to a platform variable - lzip: remove lib prefix on Linux - FindLuaJIT.cmake: add luajit-2.1 and luajit-5.1 as fallback names for the Linux install layout
On Linux, ImGui was compiled with IMGUI_IMPL_OPENGL_ES2 and linked against ANGLE's static libGLESv2. ANGLE has no active EGL context (the engine uses system GLES3 via EGL), so shader compilation fails silently every frame. Fix: on Linux use IMGUI_IMPL_OPENGL_ES3 with the system GLESv2 library so ImGui's GL calls go through the same context as the engine. Change ImGui_ImplOpenGL3_Init(nullptr) to let ImGui auto-detect the correct GLSL version from the active context.
Pass nullptr to ImGui_ImplOpenGL3_Init() so ImGui queries the active context for the correct GLSL version, rather than hardcoding "#version 100" which is invalid on GLES3 contexts.
Add linux/launcher.c which: - Locates and dlopen's libSimpleGraphic.so from its own directory - Resolves the Lua script path to absolute (so basePath inside the engine resolves correctly) - Sets SG_BASE_PATH to <pob_root>/runtime so the engine finds its data files (fonts, config) - Sets LUA_PATH to include <pob_root>/runtime/lua - Sets LUA_CPATH to include the build directory for Lua C modules - Calls RunLuaFileAsWin(argc-1, argv+1) Usage: ./PathOfBuilding src/Launch.lua
These ports are required by the Linux build: - angle: GLES/EGL implementation (used by ImGui and the render system) - openssl: required by lcurl for HTTPS support - pthread-stubs: satisfies EGL's pthread dependency on Linux
Two Linux-specific fixes applied via the build system and a new patch: 1. LUAJIT_ENABLE_GC64: LuaJIT statically linked into a dlopen'd shared library is loaded at a high virtual address. Without GC64, LuaJIT requires all GC memory within 4GB of its code section, which fails at these addresses and crashes in lua_newstate. 2. 006-fix-getenvcopy-linux.patch: The pob-wide-crt patch defines _lua_getenvcopy on non-Windows as strdup(getenv(name)). When the env var is unset, getenv returns NULL and strdup(NULL) is undefined behaviour, crashing in luaopen_package and lj_cf_os_getenv. Replace with a null-safe inline function. Also fix the circular luajit symlink in the install step and make the configure script executable before vcpkg_configure_make.
cmake --install now produces a flat directory that mirrors the Windows
runtime/ layout:
<prefix>/
PathOfBuilding # launcher
libSimpleGraphic.so # engine
socket.so, lcurl.so, lua-utf8.so, lzip.so # Lua C modules
SimpleGraphic/
Fonts/ # pre-rendered bitmap fonts
SimpleGraphic.cfg # default engine config
Font bitmaps are added to data/SimpleGraphic/Fonts/ in this repository
(they are engine assets previously bundled with PoB's runtime/).
Two CMake fixes enable the flat layout:
- Add LIBRARY DESTINATION "." to all SHARED target install rules so
Linux .so files land in the prefix root instead of lib64/.
- Install data/SimpleGraphic into the prefix alongside the binaries.
The launcher now sets SG_BASE_PATH to its own directory, so fonts are
found whether running from the build directory or an installed prefix.
Font bitmaps and SimpleGraphic.cfg already live in PoB's runtime/ directory (the same as on Windows), so there is no need to duplicate them in this repository. Remove data/SimpleGraphic/ and drop the install(DIRECTORY) rule. The natural install prefix is now the PoB runtime/ directory, where the launcher's SG_BASE_PATH logic finds the fonts automatically.
Author
|
A note on authorship: This port was developed with the assistance of Claude. I want to be fully transparent about that. That said, I'm a professional software engineer and cybersecurity practitioner — I have reviewed every change in this PR, I understand what each one does and why, and I am not just blindly applying AI suggestions. I take full ownership of this work and commit to maintaining Linux support going forward, including addressing any regressions or issues that arise on this platform. |
Contributor
|
@velomeister we have a PoB dev discord. Send me a message (Localidentity) and I'll give you an inv |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Linux Port
This document describes the changes made to build and run SimpleGraphic natively on Linux.
Overview
SimpleGraphic previously only built and ran on Windows. This work ports it to Linux (x86-64), allowing Path of Building to run natively without Wine. The engine compiles with GCC 15 on Fedora Linux and successfully launches PoB with a working window, renderer, passive tree, and network features.
All changes are backwards-compatible — the Windows build is unaffected.
How to Build (Linux)
Prerequisites:
cmake,ninja,gcc(≥ 13),pkg-config,libGL,libGLESv2,libEGL,libX11,libcurl.vcpkg handles all other dependencies automatically via the manifest.
How to Install
Install directly into PoB's
runtime/directory (where the fonts and existing data already live):This places the binaries alongside PoB's existing
runtime/SimpleGraphic/Fonts/, mirroring the Windows layout:How to Run
From the install
cd /path/to/PathOfBuilding runtime/PathOfBuilding src/Launch.luaFrom the build directory (development)
cd /path/to/PathOfBuilding LD_LIBRARY_PATH=/path/to/SimpleGraphic/build \ /path/to/SimpleGraphic/build/PathOfBuilding src/Launch.luaThe launcher resolves all paths relative to the script argument, so it must be run from the PoB repository root with
src/Launch.luaas the first argument.Changes
1. GCC 15: Missing Standard Library Headers
GCC 15 enforces stricter implicit-inclusion rules. Several translation units relied on headers being transitively included through other headers, which is no longer guaranteed.
Files:
engine/common/base64.c,engine/common/base64.h,engine/core/core_compress.cpp,engine/render/r_font.cpp,engine/render/r_main.cpp,engine/render/r_texture.cppbase64.c: add<string.h>formemset/memcpybase64.h: add<stddef.h>forsize_tcore_compress.cpp: add<cstring>formemcpyr_font.cpp: add<algorithm>forstd::find/std::minr_main.cpp: add<chrono>and<thread>r_texture.cpp: add<algorithm>and<thread>2. Type Mismatch in r_texture.cpp
4ull(unsigned long long) does not matchsize_t(unsigned long) on Linux, causing-Werror=narrowingfailures. Replace withsize_t{4}.File:
engine/render/r_texture.cpp3. Windows-only Sleep() API
Sleep(1)inGetShaderImageSizeis a Windows API. Replace with the portablestd::this_thread::sleep_for(std::chrono::milliseconds(1)).File:
engine/render/r_main.cpp4. Error() Format String Bug
Error("Exception: ", e.what())is missing a%sformat specifier, silently discarding the exception message. This is a pre-existing bug, visible on all platforms once the exception path is hit.File:
engine/system/win/sys_main.cpp5. IndexUTF8ToUTF32 Guarded by #ifdef _WIN32
IndexUTF8ToUTF32uses only standard C++ (std::string_view,char32_t,std::vector) but was inside a#ifdef _WIN32block, making it unavailable on Linux. It is called fromr_font.cppandr_main.cppon all platforms.File:
engine/common/common.cpp— move the function above the#endif.6. SpawnProcess and PlatformOpenURL for Linux
Both functions had stub implementations that printed
#warningand returned an error string.File:
engine/system/win/sys_main.cppfork/execvp. Arguments are split on whitespace, which is sufficient for PoB's usage (relaunching itself with a version flag).xdg-open, the standard Linux mechanism for opening a URL in the user's default browser.<uuid/uuid.h>which is not available on all distributions and was unused.7. Runtime Data Path: SG_BASE_PATH
On Windows, the launcher executable lives in
runtime/, soFindBasePath()(which returns the directory of the current executable via/proc/self/exe) naturally points at the right place. On Linux, the binary lives in the CMake build directory, so the data files (SimpleGraphic/Fonts/, etc.) are not found.File:
engine/system/win/sys_main.cppA new environment variable
SG_BASE_PATHis checked at the start ofFindBasePath()on Linux. If set, it is used directly. The launcher sets it to its own directory, which containsSimpleGraphic/Fonts/whether running from the build directory or an installed prefix.8. CMake Build System: Cross-Platform Lua Module Fixes
File:
CMakeLists.txt,cmake/FindLuaJIT.cmakePosition-Independent Code
Static libraries (
cmp_core,imgui) linked intolibSimpleGraphic.somust be compiled with-fPIC. AddedPOSITION_INDEPENDENT_CODE ONto both targets.-Wno-template-body
GCC 15 introduced a new warning triggered by sol2's template definitions. Suppressed with
-Wno-template-bodyon Linux.zstd: Static Fallback
vcpkg provides
zstd::libzstd_staticon Linux rather thanzstd::libzstd_shared. Use a generator expression to fall back gracefully:Lua Module
libPrefixOn Linux, CMake adds a
libprefix toSHAREDlibraries by default (e.g.libsocket.so). Lua'srequire("socket")looks forsocket.so, notlibsocket.so. AddedPREFIX ""to all Lua module targets on non-Windows:lcurl,lua-utf8,luasocket,lzip.lcurl: Duplicate Symbol
LuaJIT 2.1 exports
luaL_setfuncsas part of its Lua 5.2 compatibility layer, andl52util.c(bundled with lcurl) also defines it as a Lua 5.1 shim. On Linux this causes a duplicate symbol error at link time. Resolved with-Wl,--allow-multiple-definition.lua-utf8: LUA_BUILD_AS_DLL / INT_MAX
LUA_BUILD_AS_DLLis an MSVC-specific define. On Linux, replace it with-include limits.hto provideINT_MAX(needed by the UTF-8 library).luasocket: Platform Socket Backend
wsocket.c(Windows Sockets) is replaced withusocket.c(POSIX sockets) on Linux.wsock32andws2_32link dependencies are also made Windows-only.FindLuaJIT.cmake
Added
luajit-2.1andluajit-5.1as fallback search names for the LuaJIT header directory and library, matching the naming used by the Linux vcpkg install layout.9. ImGui: System GLES3 Instead of ANGLE
Files:
CMakeLists.txt,engine/render/r_main.cppOn Windows, ImGui is compiled with
IMGUI_IMPL_OPENGL_ES2and linked against ANGLE's staticlibGLESv2. On Linux the engine creates a GLES3 context via the system EGL driver (not ANGLE), so ANGLE's static library has no active context. Every call toglCreateShaderinside ImGui returns 0, and shader compilation fails silently on every frame.Fix: On Linux, compile ImGui with
IMGUI_IMPL_OPENGL_ES3and link against the systemGLESv2library. This makes ImGui's GL calls share the same context as the engine.Additionally,
ImGui_ImplOpenGL3_Initwas previously called with the hardcoded string"#version 100"(GLES2). Change tonullptrso ImGui queries the active context for the correct GLSL version automatically. This is correct on both Windows (resolves to"#version 100"viaIMGUI_IMPL_OPENGL_ES2) and Linux (resolves to"#version 300 es").10. Linux Launcher Binary
File:
linux/launcher.c,CMakeLists.txtA small C launcher binary (
PathOfBuilding) is built on Linux. It is the entry point for running PoB and handles the environment setup thatruntime/Path of Building.exehandles implicitly on Windows via its install layout.Responsibilities:
Load the engine:
dlopenslibSimpleGraphic.sofrom its own directory withRTLD_LAZY | RTLD_GLOBAL(RTLD_GLOBAL is required so LuaJIT's symbols are visible to dlopen'd Lua C modules likesocket.so).Resolve the script path:
realpathis called on the Lua script argument so thatbasePathinside the engine (derived from/proc/self/exe, which points at the build directory) does not interfere with relative path resolution.Set SG_BASE_PATH: Points the engine at the launcher's own directory for data files (fonts, config). This works for both the build directory and any installed prefix because
SimpleGraphic/Fonts/is installed alongside the launcher.Set LUA_PATH: Adds
<pob_root>/runtime/lua/?.luaso Lua'srequirefinds the bundled Lua modules (e.g.xml,base64,sha1). The PoB root is derived from the script path:src/Launch.lua→...Set LUA_CPATH: Adds the launcher's directory so Lua's
requirefinds the C modules (socket.so,lcurl.so,lua-utf8.so,lzip.so).11. vcpkg Overlay Ports
Files:
vcpkg-ports/,vcpkg-configuration.jsonThree additional overlay ports are required for the Linux build:
chromium_5414#9): GLES/EGL implementation. Used by ImGui and the render system. The overlay pins a specific Chromium snapshot with patches for build system compatibility.3.5.4): Required bylcurlfor HTTPS. The overlay overrides the vcpkg baseline to use a newer version with GCC 15 compatibility.0.4): Provides stub implementations of pthread functions required by EGL on Linux.12. LuaJIT Port Version 3: Linux GC64 and Null-Safe getenv
Files:
vcpkg-ports/ports/luajit/,vcpkg-ports/versions/Two Linux-specific fixes were added to the LuaJIT vcpkg port, bumping it from port-version 1 to port-version 3.
LUAJIT_ENABLE_GC64 (port-version 2)
When LuaJIT is statically linked into
libSimpleGraphic.soand the library is loaded viadlopen, the dynamic linker places the.soat a high virtual address (above 4 GB). By default, LuaJIT allocates all GC-managed memory within 4 GB of its own code section, using 32-bit relative offsets. At high addresses this constraint cannot be satisfied andlua_newstatereturns NULL, crashing immediately.Fix: Build LuaJIT with
XCFLAGS=-DLUAJIT_ENABLE_GC64, which lifts the 4 GB constraint by using full 64-bit pointers for GC objects. Applied viaportfile.cmakeinside theelseif(VCPKG_TARGET_IS_LINUX)block.006-fix-getenvcopy-linux.patch (port-version 3)
The
pob-wide-crt.patch(applied in an earlier port version) introduces a Windows-friendly_lua_getenvcopyabstraction. On non-Windows platforms it defines:When
getenvreturnsNULL(variable not set),strdup(NULL)is undefined behaviour and crashes. This affects two call sites:luaopen_package(on startup, whenLUA_PATHis unset) andlj_cf_os_getenv(at runtime, whenever Lua code callsos.getenvfor an unset variable).Fix: Replace the unsafe macro with a null-safe inline function:
Also add
#include <stdlib.h>and#include <string.h>inside the#elseblock so the inline functions have access togetenv,strdup, andfreewhen the header is compiled as a standalone translation unit.The portfile also fixes two minor Linux-specific build issues:
bin/luajit → luajit). Fixed by copying the real binary from the build tree after installation.configurewas not marked executable beforevcpkg_configure_make. Fixed withfile(CHMOD ...).13. Install Target
File:
CMakeLists.txtcmake --install build --prefix /path/to/PathOfBuilding/runtimeplaces the Linux binaries directly into PoB'sruntime/directory, whereSimpleGraphic/Fonts/already lives. The launcher'sSG_BASE_PATH = dirlogic then naturally finds the fonts alongside the installed binaries, matching the Windows layout exactly.One CMake fix was needed:
LIBRARY DESTINATION "."added to allinstall(TARGETS ... SHARED)rules. Without this, CMake's GNUInstallDirs places.sofiles inlib64/rather than the prefix root, breaking the launcher'sdlopenpath.Known Limitations
SpawnProcess argument splitting: The Linux implementation splits
argListon whitespace. Arguments containing spaces are not quoted. This is sufficient for PoB's current usage (relaunching itself) but is not a general-purpose solution.No system font fallback: The engine loads only the pre-rendered bitmap fonts shipped in
data/SimpleGraphic/Fonts/. There is no fallback to system fonts.