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) find_package(CURL 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") # index.html so the game can be served from a clean subpath URL # (e.g. https://lindholm.dev/kobo/ — no explicit filename). set(KOBO_EXEFILE "index.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 leaderboard.cpp ) if(EMSCRIPTEN) list(APPEND KOBO_SOURCES httpclient_web.cpp) else() list(APPEND KOBO_SOURCES httpclient_native.cpp) endif() 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) target_link_options(kobodl PRIVATE -sFETCH=1) else() target_link_libraries(kobodl PRIVATE CURL::libcurl) endif() 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 $ ${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 index.html / .js / .wasm / .data — install all four. install(TARGETS kobodl RUNTIME DESTINATION web) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/index.js ${CMAKE_CURRENT_BINARY_DIR}/index.wasm ${CMAKE_CURRENT_BINARY_DIR}/index.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()