Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
- uses: actions/checkout@v4

- name: Install SFML 2.x via Homebrew
run: brew install sfml@2 cmake
run: brew install sfml@2 openal-soft cmake

- name: Configure
working-directory: "SuperMario 2.0"
Expand Down
21 changes: 21 additions & 0 deletions SuperMario 2.0/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,27 @@ add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
"$<TARGET_FILE_DIR:${PROJECT_NAME}>/Levels"
)

# macOS only: SFML 2.6's audio links Apple's deprecated OpenAL.framework, which
# races in CoreAudio and crashes intermittently on launch. Ship a copy of
# libsfml-audio relinked against openal-soft beside the binary so the game uses
# a modern OpenAL instead. Requires `brew install openal-soft`.
if(APPLE)
find_library(OPENAL_SOFT_LIB NAMES openal
PATHS /opt/homebrew/opt/openal-soft/lib /usr/local/opt/openal-soft/lib
NO_DEFAULT_PATH)
if(OPENAL_SOFT_LIB)
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND bash "${CMAKE_SOURCE_DIR}/cmake/use_openal_soft.sh"
"$<TARGET_FILE:${PROJECT_NAME}>"
"$<TARGET_FILE:sfml-audio>"
"${OPENAL_SOFT_LIB}"
VERBATIM
COMMENT "Relinking libsfml-audio against openal-soft (macOS OpenAL.framework workaround)")
else()
message(WARNING "openal-soft not found - run 'brew install openal-soft' to avoid the intermittent macOS startup crash (see docs/KNOWN_ISSUES.md).")
endif()
endif()

# Headless unit tests for the pure-logic parts (no SFML / GL context needed).
enable_testing()
add_executable(SuperMario2_tests tests/tests.cpp LevelManager.cpp)
Expand Down
36 changes: 36 additions & 0 deletions SuperMario 2.0/cmake/use_openal_soft.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/usr/bin/env bash
# Ship a copy of libsfml-audio relinked against openal-soft next to the
# executable, so the game never touches Apple's deprecated, crash-prone
# OpenAL.framework (see docs/KNOWN_ISSUES.md). Invoked as a CMake POST_BUILD
# step on macOS. Idempotent: safe to re-run on every build.
#
# Args:
# $1 = path to the built executable
# $2 = path to the real libsfml-audio dylib (from SFML)
# $3 = path to openal-soft's libopenal dylib
set -euo pipefail

EXE="$1"
SFML_AUDIO="$2"
OPENAL="$3"
EXE_DIR="$(cd "$(dirname "$EXE")" && pwd)"
LOCAL="$EXE_DIR/libsfml-audio.2.6.dylib"

# Local, writable copy of libsfml-audio pointed at openal-soft.
cp -f "$SFML_AUDIO" "$LOCAL"
chmod u+w "$LOCAL"
framework=$(otool -L "$LOCAL" | awk '/OpenAL\.framework/{print $1; exit}')
if [ -n "${framework:-}" ]; then
install_name_tool -change "$framework" "$OPENAL" "$LOCAL"
fi
install_name_tool -id @rpath/libsfml-audio.2.6.dylib "$LOCAL"
codesign --force --sign - "$LOCAL"

# Point the freshly-linked executable at the local copy beside it.
current=$(otool -L "$EXE" | awk '/libsfml-audio/{print $1; exit}')
if [ "$current" != "@loader_path/libsfml-audio.2.6.dylib" ]; then
install_name_tool -change "$current" @loader_path/libsfml-audio.2.6.dylib "$EXE"
fi
codesign --force --sign - "$EXE"

echo "Relinked libsfml-audio against openal-soft: $OPENAL"
6 changes: 4 additions & 2 deletions docs/BUILD.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ The game is written in C++17 against **SFML 2.6** and built with CMake.
### macOS

```sh
brew install sfml@2 cmake
brew install sfml@2 openal-soft cmake
```

`sfml@2` is keg-only; the `CMakeLists.txt` already adds the Homebrew prefix to
the search path, so no extra flags are needed.
the search path, so no extra flags are needed. `openal-soft` is used to work
around a crash in Apple's deprecated OpenAL framework — see
[KNOWN_ISSUES.md](KNOWN_ISSUES.md).

### Ubuntu / Debian

Expand Down
45 changes: 21 additions & 24 deletions docs/KNOWN_ISSUES.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,31 @@
# Known issues

## Intermittent crash on startup (macOS, Apple Silicon)
## macOS startup crash — fixed via openal-soft

**Symptom:** the game occasionally crashes immediately on launch with
`EXC_BAD_ACCESS` / `SIGSEGV` before the window is usable. Re-launching works.
**History:** the game used to crash intermittently on launch on macOS (Apple
Silicon) with `EXC_BAD_ACCESS` before the window was usable.

**Cause:** this is *not* a bug in the game. Homebrew's `sfml@2` audio library
links Apple's **deprecated `OpenAL.framework`**:
**Cause:** Homebrew's `sfml@2` audio library links Apple's **deprecated
`OpenAL.framework`**, which races inside CoreAudio's HAL
(`AudioDeviceGetPropertyInfo`) when OpenAL first opens the audio device.

```
$ otool -L libsfml-audio.2.6.dylib | grep -i openal
/System/Library/Frameworks/OpenAL.framework/.../OpenAL
```
**Fix (automatic):** the macOS build now ships a copy of `libsfml-audio`
relinked against **openal-soft** next to the binary, so the game never touches
the Apple framework. Just install openal-soft once:

Apple deprecated that framework in macOS 10.15 and it races inside CoreAudio's
HAL (`HAL_HardwarePlugIn_ObjectHasProperty` / `AudioDeviceGetPropertyInfo`)
when OpenAL first opens the audio device. The crash happens on the first sound
played, regardless of whether it is `sf::Music` or `sf::Sound`.
```sh
brew install openal-soft
```

**Workarounds:**
CMake detects it and applies the relink as a post-build step
(`cmake/use_openal_soft.sh`). You can confirm the framework is gone:

- Use the retry launcher, which re-runs past a failed audio init:
```sh
./run.sh # from the "SuperMario 2.0" directory
```
- Or simply launch again — a successful start runs normally for the whole
session.
```sh
otool -L build/SuperMario2 build/libsfml-audio.2.6.dylib | grep -i OpenAL.framework # no output
```

**Not affected:** Linux/CI builds, which use `openal-soft` (`libopenal-dev`)
instead of the Apple framework, do not exhibit this race.
If openal-soft is **not** installed, CMake prints a warning and the game falls
back to the system framework (and the old intermittent crash). The bundled
`run.sh` retry launcher remains as a fallback for that case.

A permanent fix requires SFML to link a modern `openal-soft` on macOS, which is
a packaging concern outside this repository's source.
**Not affected:** Linux/CI uses `openal-soft` (`libopenal-dev`) already.
Loading