- C 77%
- C++ 13.2%
- Objective-C 2.3%
- Shell 1.6%
- CMake 1.6%
- Other 3.7%
make_xcframework's -headers flag baked a full copy of each library's headers into EVERY architecture slice (device AND simulator) of the xcframework itself, on top of the separate loose install/<tag>/<lib>/ include copy this script already produces and that both consuming repos actually reference in their CMake setup. Neither repo's CMake ever points at headers embedded in an xcframework -- both explicitly set their own include dirs at the loose copy -- so the embedded ones were pure duplication, multiplying an already-duplicated-across-repos header set by another 2x for nothing. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|---|---|---|
| sources | ||
| toolchain | ||
| .gitignore | ||
| build.sh | ||
| README.md | ||
SRB2 Legacy iOS static libraries
Build area for the static libraries the iOS port needs (see IOS_PORT.md in
the srb2-legacy repo). Built successfully with Xcode 27 (iOS 27 SDK) —
output/ contains all static libraries as .xcframeworks, including SDL2
and SDL2main.
This directory is self-contained: all library sources are vendored locally
under sources/ as fresh upstream downloads, not copies of the (older)
versions vendored inside the srb2-legacy repo itself.
Status
| Library | Version | Source |
|---|---|---|
| zlib | 1.3.2 | github.com/madler/zlib |
| libpng | 1.6.58 (stock, no APNG patch) | github.com/pnggroup/libpng |
| libgme | 0.6.5 | github.com/libgme/game-music-emu |
| SDL2 | 2.32.10 (patched — see below) | github.com/libsdl-org/SDL |
| SDL2_mixer | 2.8.2 (+ vendored ogg/vorbis/opus/opusfile/libxmp/wavpack) | github.com/libsdl-org/SDL_mixer |
| libopenmpt | 0.8.9 | github.com/OpenMPT/openmpt |
toolchain/ios.toolchain.cmake— the leetal/ios-cmake toolchain file used to cross-compile the CMake-based libraries with CMake's Xcode generator.build.sh— builds everything for botharm64device andarm64simulator, and packs the static libs into an.xcframeworkunderoutput/.
SDL2: backported UIScene life cycle support
Plain SDL2's iOS backend only ever implemented the classic pre-iOS-13
UIApplicationDelegate lifecycle. Starting with the iOS 27 SDK/runtime,
Apple hard-crashes any UIKit app at launch
(UIApplicationEvaluateRuntimeIssueForNoSceneLifecycleAdoption) if it hasn't
adopted the UIScene lifecycle. SDL3 fixed this properly (3.4.0+); SDL2 itself
never will, and won't going forward — SDL2 is in maintenance mode upstream.
An earlier version of this build switched the whole stack to SDL3 +
sdl2-compat (libsdl-org's shim
exposing the classic SDL2 API/ABI on top of the real SDL3 engine) to pick up
the fix for free. It worked (confirmed full rendered gameplay on an iOS 27
simulator), but sdl2-compat has no static-link mode on any platform — it
always dlopen()s the real SDL3 library at runtime — and its iOS support
turned out to be quite undertested upstream (six distinct pre-existing bugs
needed patching just to get it building and running). That's a lot of
permanent architectural complexity (dylib embedding, ad-hoc codesigning at
build time, an @rpath link setup, a stack of upstream patches to carry
forever) to buy one bugfix. Reverted as not worth it.
Instead, SDL3's actual fix is backported directly onto our vendored plain
SDL2 2.32.10, keeping everything statically linked like every other
dependency here. The fix is upstream SDL3 commit b46e26e65a ("Added support
for the UIScene life cycle on Apple platforms", fixes
libsdl-org/SDL#12680), plus
its small deprecation-warning-suppression follow-up 016a1b87a. Patched into
sources/SDL2-2.32.10/src/video/uikit/{SDL_uikitappdelegate.h,.m,SDL_uikitwindow.m}
— grep those files for "Backported from SDL3" to find every patch site.
The port is adapted, not a verbatim copy of the SDL3 diff:
- SDL2 naming conventions are preserved (
SDL_bool/SDL_TRUE/SDL_FALSEinstead ofbool/true/false,SDL_iPhoneSetEventPumpinstead ofSDL_SetiOSEventPump,TARGET_OS_TVinstead ofSDL_PLATFORM_TVOS, the 2-argumentSDL_SendDropFile(NULL, path)instead of SDL3's 3-argument version). - The new
SDLUIKitSceneDelegate(used on iOS/tvOS 13+, alongside the existingSDLUIKitDelegateas a pre-13 fallback) deliberately does not implementscene:didActivate:/sceneWillResignActive:/sceneWillEnterForeground:/sceneDidEnterBackground:: SDL2's existingSDL_uikitevents.malready observesUIApplicationDidBecomeActiveNotificationand friends viaNSNotificationCenter, which fire app-wide regardless of UIScene adoption. Adding scene-level equivalents would just callSDL_OnApplication*()a second time per transition. - The new scene delegate registers the
SDL_HINT_IDLE_TIMER_DISABLEDhint callback (SDL_AddHintCallback) inwillConnectToSession, matching what the oldSDLUIKitDelegatealready does inapplication:didFinishLaunchingWithOptions:— omitted from a literal port of the SDL3 diff, but needed here to avoid silently regressing that feature once scenes are adopted. SDL_uikitwindow.mgained aGetActiveWindowScene()helper and now creates theUIWindowviainitWithWindowScene:when a scene is available (falling back to the oldinitWithFrame:path otherwise) — aUIWindowmust be tied to a scene once the app has adopted one, or it won't actually display anything.
Verified working end-to-end: rebuilt and retested against an iPhone 18 Pro (iOS 27) simulator — boots cleanly to full initialization, WAD/asset loading, and gameplay (server start, level load), no UIApplicationEvaluateRuntimeIssueForNoSceneLifecycleAdoption crash.
libpng: no APNG patch, by instruction
This is stock libpng 1.6.58 — no APNG patch applied. Note for later,
when actually wiring this into the SRB2 iOS CMake target: srb2-legacy's
src/apng.c calls png_set_acTL/png_get_acTL, which only exist in an
APNG-patched libpng. With stock libpng those symbols don't exist, so
apng.c (the in-game APNG movie/recording feature) will fail to link as-is
on iOS — it'll need to be excluded from the iOS target or reworked. Regular
PNG screenshot saving (the non-animated path) is unaffected.
SDL2_mixer codec configuration
build.sh sets SDL2MIXER_VENDORED=ON (build codecs from bundled source,
since there's no system-installed libopus/libvorbis/libxmp/etc. to find on
iOS) and SDL2MIXER_DEPS_SHARED=OFF (link them in statically):
- OGG Vorbis →
SDL2MIXER_VORBIS=VORBISFILE(standard libogg + libvorbis + libvorbisfile), per instruction — stb_vorbis (the default) wasn't sufficient. - MOD/tracker music →
SDL2MIXER_MOD_XMP=ON(libxmp),MOD_MODPLUG=OFF. - FLAC and MP3 still default to SDL2_mixer's inline single-header vendored decoders (dr_flac, minimp3) — no external source needed for those.
- Opus/Opusfile, OGG/Vorbis, libxmp, and WavPack all need real cloned
source, so
build.shclones exactly those six submodules —ogg,vorbis,opus,opusfile,libxmp,wavpack— fromlibsdl-org's pinned forks/branches, straight intosources/SDL2_mixer-2.8.2/external/. (The release tarball ships.gitmodulesbut not the submodule contents.) - Our own separate
gme.xcframeworkandlibopenmpt.xcframeworkare unrelated to SDL2_mixer's own optionalSDL2MIXER_GME/module options, which stay off inside SDL2_mixer itself.
libopenmpt: built via its own Makefile, not its Xcode project
libopenmpt ships a checked-in build/xcode-ios/libopenmpt.xcodeproj, but
inspecting it (via its project.pbxproj, since Xcode isn't available here
to open it) showed it's not what it looks like:
- Its one target is
productType = com.apple.product-type.library.dynamic— a dynamic library, not static like the four libs above. ARCHS = "$(NATIVE_ARCH_ACTUAL)"— pinned to whatever the host machine's native architecture is, not properly parameterized per device/simulator.- No shared scheme is checked in.
- Its
ext/{ogg,vorbis,mpg123}.xcodeprojsub-projects expect upstream source manually dropped intoinclude/ogg,include/vorbis,include/mpg123— there's no submodule or download script that populates them (build/download_externals.shonly fetches unrelated Windows/DOS tooling: 7-Zip, Winamp/XMPlay SDKs, InnoSetup, etc.)
In short: this project is set up for a human opening it in Xcode and hand-configuring a destination, not for scripted device+simulator static builds — matching a 2020 OpenMPT forum thread describing the same manual massaging being necessary. Regenerating it properly requires premake/genie, which is its own yak-shave.
Instead, build.sh uses libopenmpt's plain GNU Makefile
(CONFIG=macos as the base, since it's the closest existing config to an
Apple/Clang target, already builds a static .a with DYNLINK=0), with
our own cross flags applied by baking them directly into CC/CXX
(resolved via xcrun --sdk iphoneos/iphonesimulator) rather than passing
CFLAGS/CXXFLAGS/LDFLAGS on the make command line — GNU Make locks
command-line-assigned variables, so the Makefile's own CXXFLAGS += ...
(which auto-detects and adds -std=c++20/c++23) silently no-ops against
them, leaving the build compiling pre-C++17 and failing on
constexpr if/static_assert. Baking -isysroot and
-mios-version-min/-mios-simulator-version-min into the compiler paths
themselves sidesteps that precedence trap. All optional codec dependencies
are disabled via libopenmpt's own NO_* flags (NO_ZLIB NO_MPG123 NO_OGG NO_VORBIS NO_VORBISFILE NO_FLAC NO_SNDFILE NO_PORTAUDIO NO_PORTAUDIOCPP NO_PULSEAUDIO NO_SDL2), giving a minimal, dependency-free static
libopenmpt.a with core MOD/S3M/XM/IT playback.
Device and simulator are each built in their own fresh copy of the source
tree (build/<tag>/openmpt-src/, rsynced from sources/openmpt) rather
than reusing one checkout with make clean in between: the vendored plain-C
objects (miniz/minimp3/stb_vorbis) aren't covered by libopenmpt's clean
target, so a leftover device-platform .o survived into the simulator
build (and vice versa) the first time around, producing an archive that
mixed IOS and IOSSIMULATOR object files — which -create-xcframework
correctly refused ("binaries with multiple platforms are not supported").
Confirmed fixed by checking vtool -show on an extracted object from each
platform's final .a.
Verified working: built clean end-to-end against Xcode 27 / iOS 27 SDK.
To run
cd ~/builds/srb2-legacy-ioslibs
./build.sh
Output:
output/{zlib,libpng,gme,SDL2,SDL2main,SDL2_mixer,ogg,opus,opusfile,vorbis,vorbisfile,wavpack,xmp,libopenmpt}.xcframework— static libraries, each with device + simulator arm64 slices.
Already wired into srb2-legacy-ios-slopported's thirdparty/ and CMake iOS
branch (see IOS_PORT.md); re-run this script and re-copy into that repo's
thirdparty/ if you need to rebuild from scratch.
Note: DEPLOYMENT_TARGET in build.sh is 15.0 — Xcode 27's iOS 27 SDK
only supports deployment targets from 15.0 up (13.0, used in an earlier
draft of this script, is rejected at CMake's compiler-sanity-check step).
Deliberately not built
- curl — investigated and it turned out to be dead code in srb2-legacy:
SRB2_CONFIG_HAVE_CURLis referenced insrc/CMakeLists.txtbut never declared as an actual option (unlikeHAVE_PNG/HAVE_ZLIB/HAVE_GME, which are), so thatif()block never triggers, and no.c/.hfile insrc/includes<curl/curl.h>or callscurl_easy_*. There's nothing in the actual game to link a curl build into. If networked HTTP is ever wanted on iOS (e.g. master-server queries),NSURLSessionis the natural iOS-native replacement rather than reviving curl.