Changes
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0c84c71..07d63cc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -49,23 +49,56 @@ find_package(Threads REQUIRED)
find_package(OpenSSL REQUIRED COMPONENTS Crypto)
if(NETHACK_BUILD_ENGINE)
- find_path(NETHACK_LUA_INCLUDE_DIR
- NAMES lua.h
- PATH_SUFFIXES lua5.4 lua54 lua)
- find_library(NETHACK_LUA_LIBRARY
- NAMES lua5.4 lua54 lua)
- if(NOT NETHACK_LUA_INCLUDE_DIR OR NOT NETHACK_LUA_LIBRARY)
- message(FATAL_ERROR
- "NetHack requires Lua 5.4 headers and a linkable library")
- endif()
-
- file(STRINGS "${NETHACK_LUA_INCLUDE_DIR}/lua.h"
- NETHACK_LUA_VERSION_LINE REGEX "^#define LUA_VERSION_NUM")
- if(NOT NETHACK_LUA_VERSION_LINE MATCHES "504")
- message(FATAL_ERROR
- "NetHack requires Lua 5.4 headers; found "
- "${NETHACK_LUA_INCLUDE_DIR}/lua.h")
- endif()
+ FetchContent_Declare(
+ lua
+ URL https://www.lua.org/ftp/lua-5.4.9.tar.gz
+ URL_HASH SHA256=2335b6c582a52654f94612bf10d2f4672805d05329aa6568b1d8cd9e5c6fb8e6
+ DOWNLOAD_EXTRACT_TIMESTAMP TRUE)
+ # The upstream archive has no CMakeLists.txt; MakeAvailable fetches it,
+ # and the static library target is defined here.
+ FetchContent_MakeAvailable(lua)
+
+ set(NETHACK_LUA_INCLUDE_DIR "${lua_SOURCE_DIR}/src")
+ add_library(nethack_lua STATIC
+ "${NETHACK_LUA_INCLUDE_DIR}/lapi.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/lcode.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/lctype.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/ldebug.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/ldo.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/ldump.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/lfunc.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/lgc.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/llex.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/lmem.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/lobject.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/lopcodes.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/lparser.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/lstate.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/lstring.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/ltable.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/ltm.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/lundump.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/lvm.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/lzio.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/lauxlib.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/lbaselib.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/lcorolib.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/ldblib.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/liolib.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/lmathlib.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/loadlib.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/loslib.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/lstrlib.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/ltablib.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/lutf8lib.c"
+ "${NETHACK_LUA_INCLUDE_DIR}/linit.c")
+ target_compile_features(nethack_lua PRIVATE c_std_99)
+ target_compile_definitions(nethack_lua PRIVATE LUA_USE_LINUX)
+ target_include_directories(nethack_lua PUBLIC
+ "${NETHACK_LUA_INCLUDE_DIR}")
+ target_link_libraries(nethack_lua PUBLIC m ${CMAKE_DL_LIBS})
+ set_target_properties(nethack_lua PROPERTIES
+ POSITION_INDEPENDENT_CODE ON)
FetchContent_Declare(
nethack
@@ -100,11 +133,13 @@ if(NETHACK_BUILD_ENGINE)
COMMAND "${CMAKE_COMMAND}"
"-DNETHACK_SOURCE_DIR=${NETHACK_WORK_DIR}"
"-DNETHACK_LUA_INCLUDE_DIR=${NETHACK_LUA_INCLUDE_DIR}"
- "-DNETHACK_LUA_LIBRARY=${NETHACK_LUA_LIBRARY}"
+ "-DNETHACK_LUA_LIBRARY=$<TARGET_FILE:nethack_lua>"
"-DNETHACK_COMPILER=${CMAKE_C_COMPILER}"
"-DNETHACK_ARCHIVER=${CMAKE_AR}"
-P "${CMAKE_CURRENT_SOURCE_DIR}/cmake/build_nethack.cmake"
- DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/build_nethack.cmake"
+ DEPENDS
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake/build_nethack.cmake"
+ nethack_lua
VERBATIM)
add_custom_target(nethack_engine_build
@@ -115,8 +150,7 @@ if(NETHACK_BUILD_ENGINE)
IMPORTED_LOCATION "${NETHACK_COMPAT_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES
"${NETHACK_WORK_DIR}/include"
- INTERFACE_LINK_LIBRARIES
- "${NETHACK_LUA_LIBRARY};m;dl")
+ INTERFACE_LINK_LIBRARIES nethack_lua)
add_dependencies(nethack_lib nethack_engine_build)
add_library(NetHack::libnethack ALIAS nethack_lib)
diff --git a/README.md b/README.md
index 3767dbb..f0fdc8d 100644
--- a/README.md
+++ b/README.md
@@ -7,8 +7,8 @@ records without receiving gameplay controls.
## Build
-The default build uses system Lua 5.4 headers and library. CMake checks the
-Lua header version before configuring NetHack.
+The default build fetches and statically builds Lua 5.4.9 for the NetHack
+engine, so a system Lua installation is not required.
```sh
cmake -S . -B build
diff --git a/cmake/build_nethack.cmake b/cmake/build_nethack.cmake
index c1f0872..fe73a28 100644
--- a/cmake/build_nethack.cmake
+++ b/cmake/build_nethack.cmake
@@ -18,7 +18,7 @@ set(NETHACK_COMMON_ARGS
"WANT_SYSTEM_LUA=1"
"LINUX_DISTRO=debian"
"PKG_EXISTS=yes"
- "LUA_VERSION=5.4.8"
+ "LUA_VERSION=5.4.9"
"LUAHEADERS=${NETHACK_LUA_INCLUDE_DIR}"
"LUACFLAGS=-I${NETHACK_LUA_INCLUDE_DIR}"
"LUALIBS=${NETHACK_LUA_LIBRARY} -lm -ldl")
@@ -66,12 +66,13 @@ string(REPLACE
NETHACK_END_CONTENT "${NETHACK_END_CONTENT}")
file(WRITE "${NETHACK_END_SOURCE}" "${NETHACK_END_CONTENT}")
-# The upstream libnh rule names this archive even when system Lua is used.
-# It is a dependency marker only; the executable links the system library.
+# The upstream libnh rule archives this version-named dependency. Keep an
+# empty marker here; the application links the CMake-built Lua library
+# separately because ar stores nested archives as opaque members.
file(MAKE_DIRECTORY "${NETHACK_SOURCE_DIR}/lib/lua")
execute_process(
COMMAND "${NETHACK_ARCHIVER}" rcs
- "${NETHACK_SOURCE_DIR}/lib/lua/liblua-5.4.8.a"
+ "${NETHACK_SOURCE_DIR}/lib/lua/liblua-5.4.9.a"
RESULT_VARIABLE archive_result
OUTPUT_VARIABLE archive_output
ERROR_VARIABLE archive_error)
diff --git a/designs/design-0-mcp.md b/designs/design-0-mcp.md
index 33aecb8..7d11b28 100644
--- a/designs/design-0-mcp.md
+++ b/designs/design-0-mcp.md
@@ -17,8 +17,8 @@ Confirmed requirements:
takeover mode.
- ASCII graphics are sufficient.
- Fetch NetHack, libmw, and other project dependencies through CMake
- FetchContent with pinned revisions. Common libraries such as curl and
- OpenSSL may come from the system; system Lua is also permitted.
+ FetchContent with pinned revisions. Build Lua 5.4.9 through FetchContent;
+ common platform libraries such as curl and OpenSSL may come from the system.
- This document specifies the design only; it does not authorize
implementation.
@@ -69,12 +69,11 @@ Some input is already structured: text prompts supply a buffer, menus
return selected identifiers, and extended commands return an index into
the command table. We should preserve these distinctions.
-The native library build has not yet succeeded locally. The initial
-attempt generated ignored build artifacts but failed to find its expected
-Lua dependency. System Lua 5.4.8 exists, but the upstream distribution
-detection does not recognize this Gentoo installation. The library target
-also names a bundled Lua archive explicitly. Therefore system-Lua support
-must be verified as part of implementation, not assumed from its presence.
+The NetHack library build uses the Lua headers and library fetched through
+CMake. The build adapter supplies the versioned archive marker expected by
+NetHack's Linux library rule, then links the separately built Lua library
+into the server. This avoids relying on the host distribution's Lua package
+and avoids nesting a Lua archive inside the NetHack archive.
The [official upstream library documentation](https://github.com/NetHack/NetHack/blob/NetHack-5.0/sys/libnh/README.md)
is a useful overview. Exact ABI details must come from the pinned fetched
@@ -521,19 +520,13 @@ libmw so its moving-branch declarations do not determine the versions.
Do not depend on artifacts from another project's `build/` directory.
Common platform libraries, including curl, OpenSSL, and threads, may be
-discovered through CMake package discovery or pkg-config. Prefer system
-Lua 5.4 for this build, requiring both headers and a linkable library.
-Pass the discovered include and library paths into the NetHack build
-adapter explicitly; do not rely on upstream distribution detection or
-hard-code Gentoo-specific paths. Fail configuration with a clear missing
-dependency message if compatible system Lua is unavailable. A future
-bundled Lua option must obtain its sources through FetchContent too.
-
-First validate a minimal worker linked to the actual generated `libnh.a`
-and system Lua. Resolve the system-Lua/archive mismatch in a reproducible
-build adapter or a small patch stored with the application and applied
-only to the isolated build copy. A passing header compilation
-alone is not evidence that the library can start and run a game.
+discovered through CMake package discovery or pkg-config. Keep Lua source
+fetching, its SHA-256 pin, and its static target in the CMake build. Pass the
+fetched header directory and built library path into the NetHack build
+adapter explicitly; do not rely on upstream distribution detection.
+Validate the worker against the generated `libnh.a` and the same Lua build.
+A passing header compilation alone is not evidence that the library can
+start and run a game.
Use a private application data root, configurable on the command line.
Each game gets a unique directory and a `save/` subdirectory with owner-only
diff --git a/packages/arch/PKGBUILD b/packages/arch/PKGBUILD
index 2555f4c..e3d2d35 100644
--- a/packages/arch/PKGBUILD
+++ b/packages/arch/PKGBUILD
@@ -5,8 +5,8 @@ pkgdesc='Multi-game NetHack server with an MCP interface'
arch=('x86_64')
url='https://git.xeno.darksair.org/nethack-mcp.git'
license=('custom:NetHack' 'MIT')
-depends=('curl' 'lua' 'openssl' 'sqlite' 'systemd')
-makedepends=('cmake' 'git' 'lua')
+depends=('curl' 'openssl' 'sqlite' 'systemd')
+makedepends=('cmake' 'git')
backup=('etc/nethack-mcp.toml')
source=(
'nethack-mcp::git+https://git.xeno.darksair.org/nethack-mcp.git'
@@ -34,7 +34,7 @@ build() {
-DCMAKE_INSTALL_PREFIX=/usr \
-DNETHACK_BUILD_ENGINE=ON \
-Wno-dev
- cmake --build build
+ cmake --build build -j24
}
package() {
@@ -59,4 +59,6 @@ package() {
"$pkgdir/usr/share/licenses/nethack-mcp/NetHack"
install -Dm644 "$srcdir/build/_deps/tomlplusplus-src/LICENSE" \
"$pkgdir/usr/share/licenses/nethack-mcp/MIT"
+ install -Dm644 "$srcdir/build/_deps/lua-src/src/lua.h" \
+ "$pkgdir/usr/share/licenses/nethack-mcp/Lua"
}
diff --git a/packages/arch/README.md b/packages/arch/README.md
index 303f9e5..ede0dbe 100644
--- a/packages/arch/README.md
+++ b/packages/arch/README.md
@@ -8,6 +8,8 @@ makepkg -si
The package builds the pinned NetHack engine and installs its runtime files
with the server. It does not depend on a separately installed NetHack game.
+The build also fetches and statically builds Lua 5.4.9, so it does not need a
+system Lua package.
It installs `/etc/nethack-mcp.toml`, creates the `nethack-mcp` service user
through `sysusers.d`, and provides a systemd unit.
diff --git a/src/engine_worker.cpp b/src/engine_worker.cpp
index dd2a745..4061b64 100644
--- a/src/engine_worker.cpp
+++ b/src/engine_worker.cpp
@@ -54,7 +54,7 @@ int runEngineWorker(int argc, char* argv[])
{"game_id", nullptr},
{"nethack_commit",
"c94fd5225beef48143244bfb7bc42682aad58741"},
- {"lua_version", "5.4.8"},
+ {"lua_version", "5.4.9"},
};
std::string error;
if(!channel.send(hello, error))