Skip to content

fork Build on macOS

Oznogon edited this page Jul 21, 2026 · 3 revisions

Be sure to check Build for generic instructions.

EmptyEpsilon supports building on both Intel (x86_64) and M-series ARM (M1, M2, etc.) architectures.

If you're building and running EmptyEpsilon locally for development purposes, follow the instructions in the "Basic app target" section.

If you intend to build a DMG for distribution to players that includes all necessary dependencies, follow the instructions in the "DMG packaging" section.

Basic app target

The result of these steps builds a standard macOS .app, but might require external dependencies.

  1. Install XCode:

    xcode-select --install
  2. Install the Homebrew package manager to install some dependencies before compiling EmptyEpsilon.

  3. Install cmake to compile your code, and the sdl3 dependency that EmptyEpsilon needs. You can also install git and the ninja build tool via brew if necessary.

    Note: Some users have reported build issues with cmake version 4.x. If that happens to you, try downgrading to cmake 3.31.4.

    brew install cmake sdl3 git ninja

    You can also compile or install pre-compiled SDL3 libraries yourself. Refer to the official documentation.

  4. Create a new directory named emptyepsilon where the game sources will be fetched, and download SeriousProton (game engine) and EmptyEpsilon (the actual game).

    mkdir -p emptyepsilon && cd emptyepsilon
    
    git clone https://github.com/oznogon/SeriousProton.git
    git clone https://github.com/oznogon/EmptyEpsilon.git

    If you're building a specific release of EmptyEpsilon, remember to checkout the correct tag in both repositories as mentioned in the generic Build instructions!

  5. Configure cmake.

    cmake -S EmptyEpsilon -B EmptyEpsilon/_build -G Ninja -DCMAKE_INSTALL_PREFIX=.

    The -DCMAKE_INSTALL_PREFIX=. option is necessary to install assets in the app bundle instead of /usr/local.

  6. Build EmptyEpsilon.

    cmake --build EmptyEpsilon/_build --target install

    --target install copies the repository's scripts, resources, and packs directories into the app bundle, which are required to run EmptyEpsilon. If you're rebuilding for C++ code changes without changing those directories, you can omit the --target install option to rebuild only the EmptyEpsilon binary.

Once the app bundle built, you can launch the game:

  • From Finder, by double-clicking the EmptyEpsilon app bundle in EmptyEpsilon/_build

  • From the terminal, by opening the app bundle:

    open EmptyEpsilon/_build/EmptyEpsilon.app

    To launch with Preferences file options set on the command line, pass them after the --args flag. For example, to launch the app bundle as a server into the Basic scenario by using the server_scenario option, run:

    open EmptyEpsilon/_build/EmptyEpsilon.app --args server_scenario=scenario_00_basic.lua
  • From the terminal, by directly launching the binary from the app bundle's Contents directory:

    cd EmptyEpsilon/_build/EmptyEpsilon.app/Contents
    MacOS/EmptyEpsilon

    This also outputs EmptyEpsilon's log in the terminal for easier troubleshooting.

Game assets, including models, scripts, images, sound effects, and music, are stored within the bundle at EmptyEpsilon.app/Contents/Resources/. The Preferences file (options.ini), keybindings file (keybindings.json), and script storage (scriptstorage.json) are saved to ~/.emptyepsilon/.

NOTE: The compiled app bundle still requires SDL2 libraries, such as the Homebrew sdl2 package, to be installed locally where installed. To add SDL2 to the app bundle, see DMG packaging.

If using the VSCode IDE, intellisense can be achieved for most files using the following .vscode/settings.json file:

{
  "editor.formatOnSave": false,
  "C_Cpp.default.includePath": [
    "${workspaceFolder}/src",
    "${workspaceFolder}/src/**",
    "${workspaceFolder}/../SeriousProton/src",
    "${workspaceFolder}/../SeriousProton/src/**",
    "${workspaceFolder}/_build/_deps/glm-src"
    ],
}

Targeting a minimum OS X/macOS version (optional)

To aid compatibility with specific older versions of OS X/macOS, use the MACOSX_DEPLOYMENT_TARGET environment variable to set a minimum Mac OS X/macOS target version. Setting this lower than 10.15 (EE's default since may 2021) might cause problems when compiling with newer versions of XCode, and SDL2 does not support targeting OS X 10.5 and older.

You can also set this in EmptyEpsilon's CMakeLists.txt, around the top:

set(ENV{MACOSX_DEPLOYMENT_TARGET} "11.0")

DMG packaging

Since May 2021, EE supports packaging a DMG directly through CMake that contains all necessary dependencies for distribution to players.

  1. Install the Homebrew package manager to install some dependencies before compiling EmptyEpsilon.

  2. Install cmake and ninja to be installed, which you can do via homebrew:

    brew install cmake ninja
  3. Create a folder to put all of your EmptyEpsilon files. For example, ~/Documents/emptyepsilon-compile

  4. TODO: Update this step for SDL3 Download SDL3.

    NOTE: To generate a DMG package, you cannot use the sdl2 package from homebrew!. Relocatable packages require Frameworks, which homebrew does not install.

    Frameworks and homebrew-installed libraries for SDL2 should not be installed simultaneously. However, brew's sdl2 package might be installed as a dependency of other homebrew packages, particularly ffmpeg. If you have issues building EmptyEpsilon, you might need to remove all such homebrew package dependencies so you can remove the sdl2 package.

    1. Create a folder to put your SDL2 .dmg file. For example, ~/Documents/emptyepsilon-compile/SDL2-dmg
    2. Download the official SDL2 DMG release and save it in ~/Documents/emptyepsilon-compile/SDL2-dmg.
  5. Open a terminal and change directories to ~/Documents/emptyepsilon-compile/SDL2-dmg.

  6. Run the following:

    # Update the following version number to the version you downloaded
    cd ~/Documents/emptyepsilon-compile/SDL2-dmg
    export SDL2_VERSION=2.32.10
    hdiutil attach SDL2-${SDL2_VERSION}.dmg
  7. Clone a copy of the fork's EmptyEpsilon and SeriousProton source code in ~/Documents/emptyepsilon-compile.

    cd ~/Documents/emptyepsilon-compile
    git clone https://github.com/oznogon/SeriousProton
    git clone https://github.com/oznogon/EmptyEpsilon
  8. Decide which version of EmptyEpsilon you'd like to compile. Check out the appropriate git tag:

    cd ~/Documents/emptyepsilon-compile/SeriousProton
    git checkout EE-2024.12.08
    cd ~/Documents/emptyepsilon-compile/EmptyEpsilon
    git checkout EE-2024.12.08
  9. TODO: Update this step for SDL3

    Create a sdl2-config.cmake file which targets the framework. Save it as ~/Documents/emptyepsilon-compile/sdl2-config.cmake.

    # sdl2-config.cmake
    
    # By default, hdiutil will attach to /Volumes/SDL2
    set(_SDL2_mountpoint /Volumes/SDL2)
    find_library(SDL2_LIBRARIES SDL2 PATHS "${_SDL2_mountpoint}")
    find_path(SDL2_INCLUDE_DIRS SDL.h PATHS "${SDL2_LIBRARIES}" PATH_SUFFIXES Headers)
    set(SDL2_FRAMEWORK_PATH "${_SDL2_mountpoint}/SDL2.framework")
    set(SDL2_INCLUDE_DIR  "${SDL2_FRAMEWORK_PATH}/Headers")
    set(SDL2_INCLUDE_DIRS "${SDL2_INCLUDE_DIR};${SDL2_FRAMEWORK_PATH}")
  10. Change directories to your EmptyEpsilon source code directory:

    cd ~/Documents/emptyepsilon-compile/EmptyEpsilon
  11. Run the following commands:

    1. # Run this from your EmptyEpsilon source code directory: ~/Documents/emptyepsilon-compile/EmptyEpsilon
      
      SDL2_CONFIG_DIR=..
    2. # Run this from your EmptyEpsilon source code directory: ~/Documents/emptyepsilon-compile/EmptyEpsilon
        
      # Be sure to update `DCPACK_PACKAGE_VERSION_MAJOR`, `DCPACK_PACKAGE_VERSION_MINOR`,
      # and `DCPACK_PACKAGE_VERSION_PATCH` to match the version number you've selected to compile
      
      cmake -G Ninja \
         -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo \
         -DCPACK_GENERATOR:STRING=DragNDrop \
         -DSDL2_DIR:PATH=$SDL2_CONFIG_DIR \
         -DSERIOUS_PROTON_DIR=../SeriousProton \
         -DCPACK_PACKAGE_VERSION_MAJOR=2024 \
         -DCPACK_PACKAGE_VERSION_MINOR=08 \
         -DCPACK_PACKAGE_VERSION_PATCH=09 \
         -B _build
    3. # Run this from your EmptyEpsilon source code directory: ~/Documents/emptyepsilon-compile/EmptyEpsilon
      cmake --build _build --target package --parallel
  12. If compilation finishes successfully, you should have an EmptyEpsilon .dmg in your ~/Documents/emptyepsilon-compile/EmptyEpsilon/_build/ directory, that can be used to install the game or be shared with others.

Troubleshooting

freetype (No such file or directory)

If the build fails with an error about the freetype framework being missing:

CMake Error at /usr/local/Cellar/cmake/3.22.1/share/cmake/Modules/BundleUtilities.cmake:458 (message):
  otool -l failed: 1

  error: /Library/Developer/CommandLineTools/usr/bin/otool-classic: can't
  open file: @rpath/../Frameworks/freetype.framework/Versions/A/freetype (No
  such file or directory)

You might need to install it using homebrew, and also manually link it to a path being searched during the build:

brew install freetype
ln -s /usr/local/lib/freetype.framework /Library/Frameworks/

If this still doesn't work, you may need to specify the homebrew path as a CMAKE_PREFIX_PATH when running the cmake --build command:

CMAKE_PREFIX_PATH=/usr/local/lib/freetype.framework cmake --build _build --target package --parallel

This might build the DMG, but the resulting app might still fail with a missing freetype library error, in which case ?? please help

Codesigning

SDL2 has known issues with macOS codesigning, and sometimes requires app bundles to be signed multiple times to work. If you built EmptyEpsilon from source and it won't launch, especially after rebuilding binaries in an existing app bundle, manually self-sign the bundle:

codesign --force --deep --sign - EmptyEpsilon/_build/EmptyEpsilon.app

LC_RPATH issues

If a build without C++ code changes produces a no LC_RPATH load command with path error, such as:

error: /Library/Developer/CommandLineTools/usr/bin/install_name_tool: no LC_RPATH load command with path: /opt/homebrew/Cellar/sdl2/2.32.10/lib found ...

Run cmake to configure with the -DCMAKE_SKIP_INSTALL_RPATH=TRUE flag:

cmake -S EmptyEpsilon -B EmptyEpsilon/_build -G Ninja \
    -DCMAKE_INSTALL_PREFIX=. \
    -DCMAKE_SKIP_INSTALL_RPATH=TRUE

This prevents CMake from adding install_name_tool -delete_rpath calls that succeed on the first --target install run, but then fail on re-runs because the build rpath was already removed from the installed binary.

Generic icon

If rebuilding an EmptyEpsilon app bundle from source on newer version of macOS, EmptyEpsilon's icon on the dock might revert to a white square. If so, update the last-modified timestamp on the app bundle to force a cache refresh.

touch EmptyEpsilon/_build/EmptyEpsilon.app

Clone this wiki locally