BareGit
cmake_minimum_required(VERSION 3.24)

if(NOT DEFINED NETHACK_SOURCE_DIR
   OR NOT DEFINED NETHACK_LUA_INCLUDE_DIR
   OR NOT DEFINED NETHACK_LUA_LIBRARY
   OR NOT DEFINED NETHACK_COMPILER
   OR NOT DEFINED NETHACK_ARCHIVER)
    message(FATAL_ERROR "NetHack build adapter arguments are incomplete")
endif()

find_program(NETHACK_MAKE make REQUIRED)
find_program(NETHACK_SH sh REQUIRED)

set(NETHACK_COMMON_ARGS
    "CC=${NETHACK_COMPILER}"
    "AR=${NETHACK_ARCHIVER}"
    "WANT_LIBNH=1"
    "WANT_SYSTEM_LUA=1"
    "LINUX_DISTRO=debian"
    "PKG_EXISTS=yes"
    "LUA_VERSION=5.4.9"
    "LUAHEADERS=${NETHACK_LUA_INCLUDE_DIR}"
    "LUACFLAGS=-I${NETHACK_LUA_INCLUDE_DIR}"
    "LUALIBS=${NETHACK_LUA_LIBRARY} -lm -ldl")

function(run_nethack_make)
    execute_process(
        COMMAND "${NETHACK_MAKE}" ${NETHACK_COMMON_ARGS} ${ARGN}
        WORKING_DIRECTORY "${NETHACK_SOURCE_DIR}"
        RESULT_VARIABLE result
        OUTPUT_VARIABLE output
        ERROR_VARIABLE error)
    if(NOT result EQUAL 0)
        message(FATAL_ERROR
            "NetHack make failed with ${result}\n${output}\n${error}")
    endif()
endfunction()

execute_process(
    COMMAND "${NETHACK_SH}" setup.sh hints/linux.500
    WORKING_DIRECTORY "${NETHACK_SOURCE_DIR}/sys/unix"
    RESULT_VARIABLE setup_result
    OUTPUT_VARIABLE setup_output
    ERROR_VARIABLE setup_error)
if(NOT setup_result EQUAL 0)
    message(FATAL_ERROR
        "NetHack setup failed with ${setup_result}\n"
        "${setup_output}\n${setup_error}")
endif()

# Publish NetHack's native end condition before the engine tears itself down.
set(NETHACK_END_SOURCE "${NETHACK_SOURCE_DIR}/src/end.c")
file(READ "${NETHACK_END_SOURCE}" NETHACK_END_CONTENT)
string(REPLACE
    "#include \"hack.h\""
    "#include \"hack.h\"\nextern void nethack_mcp_end_result(int) __attribute__((weak));"
    NETHACK_END_CONTENT "${NETHACK_END_CONTENT}")
string(FIND "${NETHACK_END_CONTENT}"
    "    program_state.gameover = 1;" NETHACK_END_HOOK_POSITION)
if(NETHACK_END_HOOK_POSITION EQUAL -1)
    message(FATAL_ERROR "Could not locate NetHack's terminal hook point")
endif()
string(REPLACE
    "    program_state.gameover = 1;"
    "    if (nethack_mcp_end_result)\n        nethack_mcp_end_result(how);\n    program_state.gameover = 1;"
    NETHACK_END_CONTENT "${NETHACK_END_CONTENT}")
file(WRITE "${NETHACK_END_SOURCE}" "${NETHACK_END_CONTENT}")

# 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.9.a"
    RESULT_VARIABLE archive_result
    OUTPUT_VARIABLE archive_output
    ERROR_VARIABLE archive_error)
if(NOT archive_result EQUAL 0)
    message(FATAL_ERROR
        "Could not create NetHack Lua dependency marker: ${archive_output}\n"
        "${archive_error}")
endif()

# Header generation is not safe to run concurrently with the upstream
# generated-file rules. Once it is complete, source compilation is parallel.
run_nethack_make(-j1 lua_support)
run_nethack_make(-C src -j1 pregame)
run_nethack_make(-C src -j24 libnh.a)
run_nethack_make(-j1 dlb)

# The upstream rule combines the normal Unix object list with the library
# object list. Remove the normal terminal entry points before publishing the
# archive, otherwise linking the library into a host program pulls in a
# second main() and duplicate Unix support functions.
execute_process(
    COMMAND "${NETHACK_ARCHIVER}" d libnh.a
        unixmain.o getline.o termcap.o topl.o wintty.o
    WORKING_DIRECTORY "${NETHACK_SOURCE_DIR}/src"
    RESULT_VARIABLE remove_unix_result
    OUTPUT_VARIABLE remove_unix_output
    ERROR_VARIABLE remove_unix_error)
if(NOT remove_unix_result EQUAL 0)
    message(FATAL_ERROR
        "Could not remove normal Unix objects from libnh.a: "
        "${remove_unix_output}\n${remove_unix_error}")
endif()

# The Linux libnh rule omits hacklib.o even though the normal executable
# links hacklib.a separately. Make the published library self-contained.
execute_process(
    COMMAND "${NETHACK_ARCHIVER}" rcs libnh.a hacklib.o
    WORKING_DIRECTORY "${NETHACK_SOURCE_DIR}/src"
    RESULT_VARIABLE hacklib_result
    OUTPUT_VARIABLE hacklib_output
    ERROR_VARIABLE hacklib_error)
if(NOT hacklib_result EQUAL 0)
    message(FATAL_ERROR
        "Could not add NetHack hacklib.o to libnh.a: ${hacklib_output}\n"
        "${hacklib_error}")
endif()

execute_process(
    COMMAND "${CMAKE_COMMAND}" -E copy_if_different
        "${NETHACK_SOURCE_DIR}/src/libnh.a"
        "${NETHACK_SOURCE_DIR}/src/libnethack.a"
    RESULT_VARIABLE copy_result
    OUTPUT_VARIABLE copy_output
    ERROR_VARIABLE copy_error)
if(NOT copy_result EQUAL 0)
    message(FATAL_ERROR
        "Could not publish libnethack.a compatibility name: ${copy_output}\n"
        "${copy_error}")
endif()

set(NETHACK_PLAYGROUND "${NETHACK_SOURCE_DIR}/playground")
file(MAKE_DIRECTORY "${NETHACK_PLAYGROUND}/save")

foreach(data_file nhdat symbols license)
    execute_process(
        COMMAND "${CMAKE_COMMAND}" -E copy_if_different
            "${NETHACK_SOURCE_DIR}/dat/${data_file}"
            "${NETHACK_PLAYGROUND}/${data_file}"
        RESULT_VARIABLE data_result
        OUTPUT_VARIABLE data_output
        ERROR_VARIABLE data_error)
    if(NOT data_result EQUAL 0)
        message(FATAL_ERROR
            "Could not install NetHack data file ${data_file}: "
            "${data_output}\n${data_error}")
    endif()
endforeach()

execute_process(
    COMMAND "${CMAKE_COMMAND}" -E copy_if_different
        "${NETHACK_SOURCE_DIR}/sys/libnh/sysconf"
        "${NETHACK_PLAYGROUND}/sysconf"
    RESULT_VARIABLE sysconf_result
    OUTPUT_VARIABLE sysconf_output
    ERROR_VARIABLE sysconf_error)
if(NOT sysconf_result EQUAL 0)
    message(FATAL_ERROR
        "Could not install NetHack sysconf: ${sysconf_output}\n"
        "${sysconf_error}")
endif()

foreach(runtime_file perm record logfile xlogfile livelog)
    file(WRITE "${NETHACK_PLAYGROUND}/${runtime_file}" "")
    file(CHMOD "${NETHACK_PLAYGROUND}/${runtime_file}"
        FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
endforeach()

file(CHMOD "${NETHACK_PLAYGROUND}" "${NETHACK_PLAYGROUND}/save"
    DIRECTORY_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE)

file(TOUCH "${NETHACK_SOURCE_DIR}/.nethack-library-built")