Builds a browser-playable .html/.js/.wasm/.data via `./build-web.sh` (no
new CMake top-level target — Emscripten is detected at configure time and
takes the existing kobodl through a web-flavored pipeline).
Key pieces:
- CMakeLists.txt: route SDL3 through `--use-port=sdl3`; substitute
`--use-port=libpng` for the missing sdl3_image port (Emscripten 5.0.7
ships only sdl3 + sdl3_ttf). pthread (atomics+bulk-memory) lifted to
kobo_deps so every TU agrees with wasm-ld's --shared-memory. Link with
-sASYNCIFY (avoids rewriting kobo's blocking main loop around
emscripten_set_main_loop), -sALLOW_MEMORY_GROWTH/-sMAXIMUM_MEMORY=1gb,
-sPTHREAD_POOL_SIZE=4, -lidbfs.js, and --preload-file data@/data.
- graphics/img_compat.{h,c}: libpng-backed IMG_Load shim, used in
sprite.c / gfxengine.cpp / filters.c via #include "img_compat.h".
Native builds passthrough to <SDL3_image/SDL_image.h> unchanged.
- web/shell.html: HTML wrapper that mounts /home as IDBFS for persistent
scores/config. Startup gated on addRunDependency until syncfs(true)
finishes, then /home/scores is mkdir'd post-load (the game's addPlayer
doesn't auto-create the score dir; see TODO in score.cpp).
beforeunload + visibilitychange flushes /home back to IndexedDB.
- build-web.sh: emcmake wrapper + a static server that sets the
COOP/COEP headers SharedArrayBuffer/pthreads require.
Source fixes needed to build under Emscripten's libc/libcxx:
- Renamed enemy_kind `pipe2` -> `pipe2k` (collided with libc pipe2(2)
always declared in Emscripten's <unistd.h>).
- graphics/toolkit.cpp: added missing <stdio.h> for snprintf (Emscripten's
libcxx headers don't pull it in transitively).
- states.cpp: gated the "Quit Kobo Deluxe" main-menu button on
!__EMSCRIPTEN__; exit() on the web leaves a dead canvas.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
275 lines
11 KiB
CMake
275 lines
11 KiB
CMake
cmake_minimum_required(VERSION 3.16)
|
|
project(KoboDeluxe VERSION 0.5.1 LANGUAGES C CXX)
|
|
|
|
set(CMAKE_C_STANDARD 99)
|
|
set(CMAKE_CXX_STANDARD 14)
|
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
|
|
|
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
|
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
|
|
endif()
|
|
|
|
option(KOBO_ENABLE_OPENGL "Use OpenGL rendering layer" ON)
|
|
option(KOBO_ENABLE_OSS "Build OSS audio backend (Linux)" OFF)
|
|
option(KOBO_ENABLE_ALSA "Build ALSA audio backend (Linux)" OFF)
|
|
option(KOBO_ENABLE_EPM "Extreme Pickyness Mode (-Wall -Werror)" OFF)
|
|
|
|
# Emscripten target: SDL renderer maps to WebGL, no desktop GL needed.
|
|
if(EMSCRIPTEN)
|
|
set(KOBO_ENABLE_OPENGL OFF CACHE BOOL "Use OpenGL rendering layer" FORCE)
|
|
set(KOBO_ENABLE_OSS OFF CACHE BOOL "Build OSS audio backend" FORCE)
|
|
set(KOBO_ENABLE_ALSA OFF CACHE BOOL "Build ALSA audio backend" FORCE)
|
|
endif()
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Feature detection
|
|
# ---------------------------------------------------------------------------
|
|
include(CheckIncludeFile)
|
|
include(CheckSymbolExists)
|
|
include(CheckLibraryExists)
|
|
|
|
check_include_file(dirent.h HAVE_DIRENT_H)
|
|
|
|
check_symbol_exists(getegid unistd.h HAVE_GETEGID)
|
|
check_symbol_exists(setgid unistd.h HAVE_SETGID)
|
|
check_symbol_exists(gettimeofday "sys/time.h" HAVE_GETTIMEOFDAY)
|
|
check_symbol_exists(stat "sys/stat.h" HAVE_STAT)
|
|
check_symbol_exists(snprintf stdio.h HAVE_SNPRINTF)
|
|
check_symbol_exists(vsnprintf stdio.h HAVE_VSNPRINTF)
|
|
check_symbol_exists(_snprintf stdio.h HAVE__SNPRINTF)
|
|
check_symbol_exists(_vsnprintf stdio.h HAVE__VSNPRINTF)
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Third-party libraries
|
|
# ---------------------------------------------------------------------------
|
|
# Migrating to SDL 3. Homebrew: `brew install sdl3 sdl3_image`.
|
|
# Emscripten 5.x ships an sdl3 port but no sdl3_image yet — we substitute
|
|
# libpng + a small shim (graphics/img_compat.c) for IMG_Load. The
|
|
# `--use-port` flags must appear in both compile and link phases.
|
|
if(EMSCRIPTEN)
|
|
add_library(SDL3::SDL3 INTERFACE IMPORTED)
|
|
target_compile_options(SDL3::SDL3 INTERFACE --use-port=sdl3)
|
|
target_link_options(SDL3::SDL3 INTERFACE --use-port=sdl3)
|
|
|
|
add_library(SDL3_image::SDL3_image INTERFACE IMPORTED)
|
|
target_compile_options(SDL3_image::SDL3_image INTERFACE --use-port=libpng)
|
|
target_link_options(SDL3_image::SDL3_image INTERFACE --use-port=libpng)
|
|
else()
|
|
find_package(SDL3 CONFIG REQUIRED)
|
|
find_package(SDL3_image CONFIG REQUIRED)
|
|
endif()
|
|
|
|
if(KOBO_ENABLE_OPENGL)
|
|
find_package(OpenGL)
|
|
if(OpenGL_FOUND OR OPENGL_FOUND)
|
|
set(HAVE_OPENGL 1)
|
|
endif()
|
|
endif()
|
|
|
|
if(KOBO_ENABLE_OSS)
|
|
check_include_file("sys/soundcard.h" _has_soundcard_sys)
|
|
check_include_file("soundcard.h" _has_soundcard)
|
|
if(_has_soundcard_sys OR _has_soundcard)
|
|
set(HAVE_OSS 1)
|
|
endif()
|
|
endif()
|
|
|
|
if(KOBO_ENABLE_ALSA)
|
|
find_library(ALSA_LIB asound)
|
|
check_include_file("sys/asoundlib.h" _has_asoundlib)
|
|
if(ALSA_LIB AND _has_asoundlib)
|
|
set(HAVE_ALSA 1)
|
|
endif()
|
|
endif()
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Platform-specific install layout (matches the old autotools behavior)
|
|
# ---------------------------------------------------------------------------
|
|
if(EMSCRIPTEN)
|
|
# In the browser, "data" is preloaded into Emscripten's virtual FS at /.
|
|
# Config/scores live under /home which we mount as IDBFS for persistence
|
|
# (see Module.preRun in the HTML shell / build-web.sh).
|
|
set(KOBO_BUNDLE_STYLE "web")
|
|
set(KOBO_EXEFILE "kobodl.html")
|
|
set(KOBO_DATA_DIR "/data")
|
|
set(KOBO_SCORE_DIR "/home/scores")
|
|
set(KOBO_CONFIG_DIR "/home")
|
|
set(KOBO_CONFIG_FILE ".kobodlrc")
|
|
elseif(APPLE)
|
|
set(KOBO_BUNDLE_STYLE "macosx")
|
|
set(KOBO_EXEFILE "kobodl")
|
|
set(KOBO_DATA_DIR "EXE>>../Resources")
|
|
set(KOBO_SCORE_DIR "/Library/Preferences/KoboDeluxe/scores")
|
|
set(KOBO_CONFIG_DIR "HOME>>Library/Preferences")
|
|
set(KOBO_CONFIG_FILE "KoboDeluxe Preferences")
|
|
elseif(WIN32)
|
|
set(KOBO_BUNDLE_STYLE "simple")
|
|
set(KOBO_EXEFILE "kobodl.exe")
|
|
set(KOBO_DATA_DIR "EXE>>")
|
|
set(KOBO_SCORE_DIR "EXE>>scores")
|
|
set(KOBO_CONFIG_DIR "EXE>>")
|
|
set(KOBO_CONFIG_FILE "kobodl.cfg")
|
|
else()
|
|
set(KOBO_BUNDLE_STYLE "unix")
|
|
set(KOBO_EXEFILE "kobodl")
|
|
set(KOBO_DATA_DIR "${CMAKE_INSTALL_PREFIX}/share/kobo-deluxe")
|
|
set(KOBO_SCORE_DIR "${CMAKE_INSTALL_PREFIX}/var/lib/kobo-deluxe/scores")
|
|
set(KOBO_CONFIG_DIR "HOME>>")
|
|
set(KOBO_CONFIG_FILE ".kobodlrc")
|
|
endif()
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Generated headers
|
|
# ---------------------------------------------------------------------------
|
|
configure_file(
|
|
${CMAKE_CURRENT_SOURCE_DIR}/aconfig.h.cmake.in
|
|
${CMAKE_CURRENT_BINARY_DIR}/aconfig.h
|
|
@ONLY
|
|
)
|
|
|
|
if(APPLE)
|
|
configure_file(
|
|
${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.cmake.in
|
|
${CMAKE_CURRENT_BINARY_DIR}/Info.plist
|
|
@ONLY
|
|
)
|
|
endif()
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Shared interface target — every component links this for flags/defines/SDL
|
|
# ---------------------------------------------------------------------------
|
|
add_library(kobo_deps INTERFACE)
|
|
target_compile_definitions(kobo_deps INTERFACE
|
|
HAVE_CONFIG_H
|
|
KOBO_DATA_DIR="${KOBO_DATA_DIR}"
|
|
KOBO_SCORE_DIR="${KOBO_SCORE_DIR}"
|
|
KOBO_CONFIG_DIR="${KOBO_CONFIG_DIR}"
|
|
KOBO_CONFIG_FILE="${KOBO_CONFIG_FILE}"
|
|
SYSCONF_DIR="${CMAKE_INSTALL_PREFIX}/etc"
|
|
)
|
|
target_include_directories(kobo_deps INTERFACE
|
|
${CMAKE_CURRENT_BINARY_DIR} # for generated aconfig.h
|
|
${CMAKE_CURRENT_SOURCE_DIR} # for config.h
|
|
)
|
|
target_link_libraries(kobo_deps INTERFACE SDL3::SDL3 SDL3_image::SDL3_image)
|
|
|
|
if(HAVE_OPENGL)
|
|
target_compile_definitions(kobo_deps INTERFACE HAVE_OPENGL)
|
|
target_link_libraries(kobo_deps INTERFACE OpenGL::GL)
|
|
endif()
|
|
if(HAVE_OSS)
|
|
target_compile_definitions(kobo_deps INTERFACE HAVE_OSS)
|
|
endif()
|
|
if(HAVE_ALSA)
|
|
target_compile_definitions(kobo_deps INTERFACE HAVE_ALSA)
|
|
target_link_libraries(kobo_deps INTERFACE ${ALSA_LIB})
|
|
endif()
|
|
|
|
if(UNIX AND NOT APPLE)
|
|
target_link_libraries(kobo_deps INTERFACE m)
|
|
endif()
|
|
|
|
if(EMSCRIPTEN)
|
|
# -pthread enables wasm atomics+bulk-memory; every TU must agree on it or
|
|
# wasm-ld rejects --shared-memory.
|
|
target_compile_options(kobo_deps INTERFACE -pthread)
|
|
target_link_options(kobo_deps INTERFACE -pthread)
|
|
endif()
|
|
|
|
if(KOBO_ENABLE_EPM)
|
|
target_compile_options(kobo_deps INTERFACE
|
|
-Wall -Werror -Wwrite-strings -fno-builtin
|
|
)
|
|
endif()
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Subprojects
|
|
# ---------------------------------------------------------------------------
|
|
add_subdirectory(graphics)
|
|
add_subdirectory(sound)
|
|
add_subdirectory(eel)
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Main executable
|
|
# ---------------------------------------------------------------------------
|
|
set(KOBO_SOURCES
|
|
enemies.cpp enemy.cpp pfile.cpp gamectl.cpp manage.cpp map.cpp
|
|
myship.cpp radar.cpp random.cpp scenes.cpp score.cpp screen.cpp
|
|
filemap.cpp prefs.cpp cfgform.cpp options.cpp gamestate.cpp
|
|
states.cpp form.cpp cfgparse.cpp game.cpp kobo.cpp logger.c
|
|
dashboard.cpp sound.cpp prof.cpp bench.cpp
|
|
)
|
|
|
|
add_executable(kobodl ${KOBO_SOURCES})
|
|
target_include_directories(kobodl PRIVATE ${CMAKE_SOURCE_DIR}/data/sfx)
|
|
target_link_libraries(kobodl PRIVATE graphics sound eel kobo_deps)
|
|
set_target_properties(kobodl PROPERTIES OUTPUT_NAME ${KOBO_EXEFILE})
|
|
|
|
if(EMSCRIPTEN)
|
|
# ASYNCIFY lets the existing blocking main loop (gengine->run(), SDL_Delay)
|
|
# yield to the browser without rewriting it around emscripten_set_main_loop.
|
|
# pthread (atomics+bulk-memory) is applied via kobo_deps for every TU.
|
|
# The data directory is baked into the .data sidecar via --preload-file.
|
|
target_link_options(kobodl PRIVATE
|
|
-sASYNCIFY=1
|
|
-sALLOW_MEMORY_GROWTH=1
|
|
-sINITIAL_MEMORY=128MB
|
|
-sMAXIMUM_MEMORY=1gb
|
|
-sPTHREAD_POOL_SIZE=4
|
|
-sEXIT_RUNTIME=1
|
|
-sFORCE_FILESYSTEM=1
|
|
-sEXPORTED_RUNTIME_METHODS=FS,callMain
|
|
-lidbfs.js
|
|
--preload-file ${CMAKE_SOURCE_DIR}/data@/data
|
|
)
|
|
# Generate index.html alongside kobodl.html so it can be served as the
|
|
# default document. The shell file mounts /home as IDBFS for persistence.
|
|
if(EXISTS ${CMAKE_SOURCE_DIR}/web/shell.html)
|
|
target_link_options(kobodl PRIVATE
|
|
--shell-file ${CMAKE_SOURCE_DIR}/web/shell.html)
|
|
endif()
|
|
set_target_properties(kobodl PROPERTIES SUFFIX "")
|
|
endif()
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Install rules
|
|
# ---------------------------------------------------------------------------
|
|
if(KOBO_BUNDLE_STYLE STREQUAL "macosx")
|
|
# Build a .app bundle alongside the binary.
|
|
set(KOBO_APP_DIR ${CMAKE_BINARY_DIR}/KoboDeluxe.app)
|
|
add_custom_command(TARGET kobodl POST_BUILD
|
|
COMMAND ${CMAKE_COMMAND} -E make_directory ${KOBO_APP_DIR}/Contents/MacOS
|
|
COMMAND ${CMAKE_COMMAND} -E make_directory ${KOBO_APP_DIR}/Contents/Resources
|
|
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/Info.plist ${KOBO_APP_DIR}/Contents/Info.plist
|
|
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:kobodl> ${KOBO_APP_DIR}/Contents/MacOS/
|
|
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/data/gfx ${KOBO_APP_DIR}/Contents/Resources/gfx
|
|
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/data/sfx ${KOBO_APP_DIR}/Contents/Resources/sfx
|
|
COMMENT "Assembling KoboDeluxe.app bundle"
|
|
VERBATIM
|
|
)
|
|
install(DIRECTORY ${KOBO_APP_DIR} DESTINATION /Applications USE_SOURCE_PERMISSIONS)
|
|
elseif(KOBO_BUNDLE_STYLE STREQUAL "simple")
|
|
install(TARGETS kobodl RUNTIME DESTINATION KoboDeluxe)
|
|
install(DIRECTORY data/gfx data/sfx DESTINATION KoboDeluxe)
|
|
install(FILES COPYING COPYING.LIB README ChangeLog TODO DESTINATION KoboDeluxe)
|
|
elseif(KOBO_BUNDLE_STYLE STREQUAL "web")
|
|
# Emscripten emits kobodl.html / .js / .wasm / .data — install all four.
|
|
install(TARGETS kobodl RUNTIME DESTINATION web)
|
|
install(FILES
|
|
${CMAKE_CURRENT_BINARY_DIR}/kobodl.js
|
|
${CMAKE_CURRENT_BINARY_DIR}/kobodl.wasm
|
|
${CMAKE_CURRENT_BINARY_DIR}/kobodl.data
|
|
DESTINATION web OPTIONAL)
|
|
else()
|
|
include(GNUInstallDirs)
|
|
install(TARGETS kobodl RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
|
install(FILES kobodl.6 DESTINATION ${CMAKE_INSTALL_MANDIR}/man6)
|
|
install(DIRECTORY data/gfx data/sfx
|
|
DESTINATION ${CMAKE_INSTALL_DATADIR}/kobo-deluxe)
|
|
install(DIRECTORY DESTINATION ${KOBO_SCORE_DIR}
|
|
DIRECTORY_PERMISSIONS
|
|
OWNER_READ OWNER_WRITE OWNER_EXECUTE
|
|
GROUP_READ GROUP_WRITE GROUP_EXECUTE
|
|
WORLD_READ WORLD_WRITE WORLD_EXECUTE)
|
|
endif()
|