miki151 / keeperrl

Source code of KeeperRL
GNU General Public License v2.0
890 stars 112 forks source link

Apple Silicon build instructions. #1991

Open nega0 opened 1 year ago

nega0 commented 1 year ago

Running Apple Silicon? Not using Rosetta? Here's how to get a native build with graphics and music.

These instructions assume you have Homebrew properly installed and know how to use it. They also assume that you're familiar with using the terminal.

Buy KeeperRL

If you want to support @miki151 (of course you do) buy it from him or get it from the Humble store. I got my copy from the KeeperRL website, not Steam, nor Itch.io. The file I ended downloading was keeperRL_alpha35_hotfix4_osx.zip.

Unzip KeeperRL

Open your terminal, unzip KeeperRL, try to play, and be sad :sob:.

$ cd ~/Downloads
$ unzip keeperRL_alpha35_hotfix4_osx.zip
$ cd keeperRL_alpha35_hotfix4
$ ./keeper_mac.command
Running the game from .
./keeper_mac.command: line 12: ./keeper: Bad CPU type in executable

Install a few things from Homebrew

There may be more, but you definitely need these.

$ brew install cmake
$ brew install sdl2 sdl2_image
$ brew install libogg libvorbis theora

Get the KeeperRL source

There have been some recent changes to the stable branch, that require Steamworks. Hopefully that will be straightened out soon (see #1990), and we won't need to checkout an older revision.

$ cd ~/Downloads
$ git clone https://github.com/miki151/keeperrl.git
$ cd keeperrl
$ git checkout 894e69df

Fix a file by hand

KeeperRL supplies 2 copies of a file with different cases in the file name. Apple filesystems are case-insensitive by default, so let's fix that. (And the following patch expects this.) This assumes we're still in checkout directory from the previous step.

$ mv cmake/FindOgg.cmake cmake/FindOGG.cmake

Apply the patch

Copy this patch to your clipboard with Cmd-C or the hover-over button

```diff diff --git a/.gitignore b/.gitignore index f40599b4..390b8f05 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,10 @@ gen_version log.gz libsteam_api.so worldgen_out.txt + +# cmake artefacts +CMakeCache.txt +CMakeFiles/ +cmake_install.cmake +compile_commands.json +Makefile diff --git a/CMakeLists.txt b/CMakeLists.txt index d2ccab68..c4780b7b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,35 +1,43 @@ -cmake_minimum_required (VERSION 2.6) +cmake_minimum_required (VERSION 3.16) project(keeper) + +set(CMAKE_CXX_STANDARD 14) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + # set default cxxflags -set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++1y -Wno-sign-compare -Wno-unused-variable -Wno-shift-count-overflow -ftemplate-depth=512 -DUSE_STEAMWORKS -I /home/michal/keeperrl/extern/steamworks/public") +add_compile_options("-Wall" "-Wno-sign-compare" "-Wno-unused-variable" "-Wno-shift-count-overflow" "-ftemplate-depth=512") # clang specific cflags if(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-tautological-constant-out-of-range-compare -Wno-mismatched-tags") + add_compile_options("-Wno-tautological-constant-out-of-range-compare" "-Wno-mismatched-tags") endif() set(STDAFX_H "${CMAKE_CURRENT_SOURCE_DIR}/stdafx.h") set(STDAFX_H_GCH "${CMAKE_CURRENT_BINARY_DIR}/stdagx.h.gch") # set debug cxxflags -set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wimplicit-fallthrough -Wno-unused-function") -#if ((${CMAKE_BUILD_TYPE} MATCHES "Debug") AND (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")) -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=lld -L ${CMAKE_CURRENT_SOURCE_DIR}/extern/steamworks/redistributable_bin/linux64/ -L /usr/local/lib -lsteam_api -Wl,-rpath=. -Wl,--gdb-index") - #endif() +if ((${CMAKE_BUILD_TYPE} MATCHES "Debug")) + add_compile_options("-Wimplicit-fallthrough" "-Wno-unused-function") + #if(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")) + #set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=lld -L ${CMAKE_CURRENT_SOURCE_DIR}/extern/steamworks/redistributable_bin/linux64/ -L /usr/local/lib -lsteam_api -Wl,-rpath=. -Wl,--gdb-index") + #endif() +endif() # additional cmake modules directory set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/") +# use steamworks? +option(USE_STEAMWORKS "Use Steamsworks" OFF) + # find required libraries find_package(SDL2 REQUIRED) find_package(SDL2_image REQUIRED) find_package(OpenGL REQUIRED) -find_package (Threads REQUIRED) +find_package(Threads REQUIRED) find_package(CURL REQUIRED) find_package(ZLIB REQUIRED) find_package(OpenAL REQUIRED) find_package(Vorbis REQUIRED) -find_package(Ogg REQUIRED) +find_package(OGG REQUIRED) find_package(VorbisFile REQUIRED) find_package(THEORA REQUIRED) @@ -58,17 +66,25 @@ add_custom_command( # rules to create `keeper` binary file(GLOB SOURCES "*.cpp" "extern/*.cpp") +if(NOT USE_STEAMWORKS) + file(GLOB STEAM_SOURCES "steam_*.cpp") + list(REMOVE_ITEM SOURCES ${STEAM_SOURCES}) +endif() + add_executable(keeper ${SOURCES} ${KEEPER_VERSION_H} ${CHECK_SERIAL_STAMP}) +target_compile_options(keeper PUBLIC "-Wno-deprecated-declarations") # kick std::random_shuffle down the road target_include_directories(keeper PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) target_include_directories(keeper PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/extern) -target_include_directories(keeper PRIVATE ${SDL2_INCLUDE_DIRS}) -target_link_libraries(keeper PRIVATE - ${SDL2_LIBRARIES} - ${SDL2_IMAGE_LIBRARY} - ${OPENGL_gl_LIBRARY} - ${CMAKE_THREAD_LIBS_INIT} - ${CURL_LIBRARIES} - ${ZLIB_LIBRARIES} +target_include_directories(keeper PRIVATE ${VORBIS_INCLUDE_DIRS}) +target_include_directories(keeper PRIVATE ${THEORA_INCLUDE_DIRS}) +target_include_directories(keeper PRIVATE ${OPENAL_INCLUDE_DIR}) +target_link_libraries(keeper PRIVATE + SDL2::SDL2 + SDL2_image::SDL2_image + OpenGL::GL + Threads::Threads + CURL::libcurl + ZLIB::ZLIB ${OPENAL_LIBRARY} ${VORBIS_LIBRARIES} ${OGG_LIBRARIES} @@ -76,25 +92,18 @@ target_link_libraries(keeper PRIVATE ${VorbisFile_LIBRARIES} ) +# setup steamworks +if(USE_STEAMWORKS) + target_compile_definitions(keeper PRIVATE USE_STEAMWORKS) + target_include_directories(keeper PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/extern/steamworks/public") +endif() + # set up definitions if ((${CMAKE_BUILD_TYPE} MATCHES "Release")) target_compile_definitions(keeper PRIVATE RELEASE=1) else() -# generate stdafx.h.gch for debug build -# workaround to unquote the cxxflags -set(CXX_FLAGS_LIST ${CMAKE_CXX_FLAGS}) -separate_arguments(CXX_FLAGS_LIST) -add_custom_command( - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/ - COMMAND ${CMAKE_CXX_COMPILER} ${CXX_FLAGS_LIST} -x c++-header ${STDAFX_H} -MMD -o ${STDAFX_H_GCH} - DEPENDS ${STDAFX_H} - OUTPUT ${STDAFX_H_GCH} - COMMENT "Generating ${STDAFX_H_GCH}" -) -if(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -include-pch ${STDAFX_H_GCH}") -endif() -target_sources(keeper PRIVATE ${STDAFX_H_GCH}) + # generate stdafx.h.gch for debug build + target_precompile_headers(keeper PRIVATE stdafx.h) endif() if(ENABLE_LOCAL_USER_DIR) diff --git a/audio_device.cpp b/audio_device.cpp index a6292be6..e8c1e8af 100644 --- a/audio_device.cpp +++ b/audio_device.cpp @@ -1,7 +1,12 @@ #include "stdafx.h" +#ifdef __APPLE__ +#include "al.h" +#include "alc.h" +#else #include #include +#endif #include diff --git a/check_serial.sh b/check_serial.sh index f6a50b9a..a22990a4 100644 --- a/check_serial.sh +++ b/check_serial.sh @@ -6,11 +6,11 @@ grep -o "SERIAL(.*)" *.{h,cpp} | grep -v "serialization\." | cut -d"(" -f 2 | cu grep -E "(SERIALIZE_ALL\(|SERIALIZE_ALL_NO_VERSION\(|COMPARE_ALL\()" *.{h,cpp} | grep -v define | eval $GET_ARGUMENTS | sed "s/, /\n/g" > /tmp/def1 grep " ar(" *.{cpp,h} | grep -v define | eval $GET_ARGUMENTS | sed "s/, /\n/g" >> /tmp/def1 grep -E "(SERIALIZE_DEF\(|SERIALIZE_TMPL\()" *.cpp | grep -v define | eval $GET_ARGUMENTS | grep , | cut -d" " -f 2- | sed "s/, /\n/g" >> /tmp/def1 -sed -i "s/NAMED(\(.*\))/\1/" /tmp/def1 -sed -i "s/SKIP(\(.*\))/\1/" /tmp/def1 -sed -i "s/OPTION(\(.*\))/\1/" /tmp/def1 -sed -i "s/withRoundBrackets(\(.*\))/\1/" /tmp/def1 -sed -i "s/serializeAsValue(\(.*\))/\1/" /tmp/def1 +sed -i~ "s/NAMED(\(.*\))/\1/" /tmp/def1 +sed -i~ "s/SKIP(\(.*\))/\1/" /tmp/def1 +sed -i~ "s/OPTION(\(.*\))/\1/" /tmp/def1 +sed -i~ "s/withRoundBrackets(\(.*\))/\1/" /tmp/def1 +sed -i~ "s/serializeAsValue(\(.*\))/\1/" /tmp/def1 grep -v SUBCLASS < /tmp/def1 | grep -v __VA_ARGS__ | grep -v 'roundBracket()' | grep -v "endInput()" | sort > /tmp/def diff /tmp/decl /tmp/def diff --git a/cmake/FindSDL2_image.cmake b/cmake/FindSDL2_image.cmake deleted file mode 100644 index 19cb2a97..00000000 --- a/cmake/FindSDL2_image.cmake +++ /dev/null @@ -1,102 +0,0 @@ -# Distributed under the OSI-approved BSD 3-Clause License. See accompanying -# file Copyright.txt or https://cmake.org/licensing for details. - -#.rst: -# FindSDL2_image -# ------------- -# -# Locate SDL2_image library -# -# This module defines: -# -# :: -# -# SDL2_IMAGE_LIBRARIES, the name of the library to link against -# SDL2_IMAGE_INCLUDE_DIRS, where to find the headers -# SDL2_IMAGE_FOUND, if false, do not try to link against -# SDL2_IMAGE_VERSION_STRING - human-readable string containing the -# version of SDL2_image -# -# -# -# For backward compatibility the following variables are also set: -# -# :: -# -# SDL2IMAGE_LIBRARY (same value as SDL2_IMAGE_LIBRARIES) -# SDL2IMAGE_INCLUDE_DIR (same value as SDL2_IMAGE_INCLUDE_DIRS) -# SDL2IMAGE_FOUND (same value as SDL2_IMAGE_FOUND) -# -# -# -# $SDLDIR is an environment variable that would correspond to the -# ./configure --prefix=$SDLDIR used in building SDL. -# -# Created by Eric Wing. This was influenced by the FindSDL.cmake -# module, but with modifications to recognize OS X frameworks and -# additional Unix paths (FreeBSD, etc). - -if(NOT SDL2_IMAGE_INCLUDE_DIR AND SDL2IMAGE_INCLUDE_DIR) - set(SDL2_IMAGE_INCLUDE_DIR ${SDL2IMAGE_INCLUDE_DIR} CACHE PATH "directory cache -entry initialized from old variable name") -endif() -find_path(SDL2_IMAGE_INCLUDE_DIR SDL_image.h - HINTS - ENV SDL2IMAGEDIR - ENV SDL2DIR - ${SDL2_DIR} - PATH_SUFFIXES SDL2 - # path suffixes to search inside ENV{SDL2DIR} - include/SDL2 include -) - -if(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(VC_LIB_PATH_SUFFIX lib/x64) -else() - set(VC_LIB_PATH_SUFFIX lib/x86) -endif() - -if(NOT SDL2_IMAGE_LIBRARY AND SDL2IMAGE_LIBRARY) - set(SDL2_IMAGE_LIBRARY ${SDL2IMAGE_LIBRARY} CACHE FILEPATH "file cache entry -initialized from old variable name") -endif() -find_library(SDL2_IMAGE_LIBRARY - NAMES SDL2_image - HINTS - ENV SDL2IMAGEDIR - ENV SDL2DIR - ${SDL2_DIR} - PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX} -) - -if(SDL2_IMAGE_INCLUDE_DIR AND EXISTS "${SDL2_IMAGE_INCLUDE_DIR}/SDL2_image.h") - file(STRINGS "${SDL2_IMAGE_INCLUDE_DIR}/SDL2_image.h" SDL2_IMAGE_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL2_IMAGE_MAJOR_VERSION[ \t]+[0-9]+$") - file(STRINGS "${SDL2_IMAGE_INCLUDE_DIR}/SDL2_image.h" SDL2_IMAGE_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL2_IMAGE_MINOR_VERSION[ \t]+[0-9]+$") - file(STRINGS "${SDL2_IMAGE_INCLUDE_DIR}/SDL2_image.h" SDL2_IMAGE_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL2_IMAGE_PATCHLEVEL[ \t]+[0-9]+$") - string(REGEX REPLACE "^#define[ \t]+SDL2_IMAGE_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_IMAGE_VERSION_MAJOR "${SDL2_IMAGE_VERSION_MAJOR_LINE}") - string(REGEX REPLACE "^#define[ \t]+SDL2_IMAGE_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_IMAGE_VERSION_MINOR "${SDL2_IMAGE_VERSION_MINOR_LINE}") - string(REGEX REPLACE "^#define[ \t]+SDL2_IMAGE_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_IMAGE_VERSION_PATCH "${SDL2_IMAGE_VERSION_PATCH_LINE}") - set(SDL2_IMAGE_VERSION_STRING ${SDL2_IMAGE_VERSION_MAJOR}.${SDL2_IMAGE_VERSION_MINOR}.${SDL2_IMAGE_VERSION_PATCH}) - unset(SDL2_IMAGE_VERSION_MAJOR_LINE) - unset(SDL2_IMAGE_VERSION_MINOR_LINE) - unset(SDL2_IMAGE_VERSION_PATCH_LINE) - unset(SDL2_IMAGE_VERSION_MAJOR) - unset(SDL2_IMAGE_VERSION_MINOR) - unset(SDL2_IMAGE_VERSION_PATCH) -endif() - -set(SDL2_IMAGE_LIBRARIES ${SDL2_IMAGE_LIBRARY}) -set(SDL2_IMAGE_INCLUDE_DIRS ${SDL2_IMAGE_INCLUDE_DIR}) - -include(FindPackageHandleStandardArgs) - -FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2_image - REQUIRED_VARS SDL2_IMAGE_LIBRARIES SDL2_IMAGE_INCLUDE_DIRS - VERSION_VAR SDL2_IMAGE_VERSION_STRING) - -# for backward compatibility -set(SDL2IMAGE_LIBRARY ${SDL2_IMAGE_LIBRARIES}) -set(SDL2IMAGE_INCLUDE_DIR ${SDL2_IMAGE_INCLUDE_DIRS}) -set(SDL2IMAGE_FOUND ${SDL2_IMAGE_FOUND}) - -mark_as_advanced(SDL2_IMAGE_LIBRARY SDL2_IMAGE_INCLUDE_DIR) diff --git a/fx_math.cpp b/fx_math.cpp index 83ca6ba3..8e2ec418 100644 --- a/fx_math.cpp +++ b/fx_math.cpp @@ -1,7 +1,7 @@ #include "fx_math.h" #include -#ifdef OSX +#ifdef __APPLE__ void sincosf(float a, float* sin, float* cos) { __sincosf(a, sin, cos); } diff --git a/fx_math.h b/fx_math.h index cf4aab70..83fdd7d9 100644 --- a/fx_math.h +++ b/fx_math.h @@ -4,7 +4,7 @@ #include #include -#ifdef OSX +#ifdef __APPLE__ void sincosf(float a, float* sin, float* cos); #endif diff --git a/model_builder.cpp b/model_builder.cpp index ca5f721d..28431fcc 100644 --- a/model_builder.cpp +++ b/model_builder.cpp @@ -337,7 +337,7 @@ void ModelBuilder::measureModelGen(const string& name, int numTries, function(steady_clock::now() - time).count(); sumT += millis; maxT = max(maxT, millis); diff --git a/opengl.cpp b/opengl.cpp index c9216e2d..d1fc79e2 100644 --- a/opengl.cpp +++ b/opengl.cpp @@ -107,7 +107,7 @@ static void APIENTRY debugOutputCallback(GLenum source, GLenum type, GLuint id, } bool installOpenglDebugHandler() { -#ifndef OSX +#ifndef __APPLE__ #ifndef RELEASE static bool isInitialized = false, properlyInitialized = false; if (isInitialized) diff --git a/stdafx.h b/stdafx.h index 506ec140..a8a9bf01 100644 --- a/stdafx.h +++ b/stdafx.h @@ -65,7 +65,7 @@ // Use boost threads on OSX to use the main thread for rendering // and set a large stack size for the model thread. -//#ifdef OSX +//#ifdef __APPLE__ //#include //#else #include @@ -126,7 +126,7 @@ using std::uint8_t; using std::recursive_mutex; typedef std::unique_lock RecursiveLock; -/*#ifdef OSX +/*#ifdef __APPLE__ using boost::thread; using boost::this_thread::sleep_for; using boost::chrono::duration; diff --git a/util.cpp b/util.cpp index c6c16b07..79544e33 100644 --- a/util.cpp +++ b/util.cpp @@ -996,7 +996,7 @@ AsyncLoop::~AsyncLoop() { } -/*#ifdef OSX // see thread comment in stdafx.h +/*#ifdef __APPLE__ // see thread comment in stdafx.h static thread::attributes getAttributes() { thread::attributes attr; attr.set_stack_size(4096 * 4000); @@ -1222,8 +1222,10 @@ string toPercentage(double v) { } void openUrl(const string& url) { -#if defined(WINDOWS) || defined(OSX) +#if defined(WINDOWS) system(("cmd /c start " + url).data()); +#elif defined(__APPLE__) + system(("open " + url).data()); #else system(("xdg-open " + url).data()); #endif ```

Once the patch is copied to your clipboard, apply the patch. This assumes we're still in checkout directory from the previous step.

$ pbpaste | patch -p1

Build the patched sources

This assumes we're still in our checkout directory.

$ cmake -DCMAKE_BUILD_TYPE=Release .
$ make

Link the data files from our purchased copy of KeeperRL

You did buy it, didn't you?

$ ln -s ../keeperRL_alpha35_hotfix4/data

Play KeeperRL

Once you execute the following command, it'll feel like nothing's happening. Give it a moment and it'll start.

$ ./keeper
nega0 commented 1 year ago

@miki151 I'm happy to send the above patch as a PR, but since it's against a prior rev, I don't know how useful that would be.