|
| 1 | +#!/usr/bin/env bash |
| 2 | +# Localize all non-exported symbols in an Apple static library so that its |
| 3 | +# bundled mimalloc does not coalesce with Unity 6.5's built-in mimalloc when the |
| 4 | +# library is statically linked into UnityFramework (iOS `__Internal`). |
| 5 | +# |
| 6 | +# Requires the library to have been compiled with `-fno-common` (see the CI |
| 7 | +# workflow) so that mimalloc's tentative definitions (e.g. `_mi_page_map`) are |
| 8 | +# real defined symbols rather than common symbols, which cannot be localized. |
| 9 | +# |
| 10 | +# Usage: localize-apple-staticlib.sh <lib.a> <ld-arch> [sdk] [platform] [min-os] |
| 11 | +# e.g. localize-apple-staticlib.sh libunienc_c.a arm64 iphoneos ios 13.0 |
| 12 | +set -euo pipefail |
| 13 | + |
| 14 | +LIB="$1" # path to the .a (e.g. libunienc_c.a) |
| 15 | +ARCH="$2" # ld arch name (e.g. arm64) |
| 16 | +SDK="${3:-iphoneos}" # xcrun SDK (e.g. iphoneos) |
| 17 | +PLATFORM="${4:-ios}" # -platform_version platform name (e.g. ios) |
| 18 | +MIN_OS="${5:-13.0}" # -platform_version minimum OS version |
| 19 | +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" |
| 20 | +EXPORTS="$SCRIPT_DIR/../../InstantReplay.Externals/unienc/crates/unienc_c/apple-exports.txt" |
| 21 | + |
| 22 | +if [ ! -f "$LIB" ]; then |
| 23 | + echo "ERROR: static library not found: $LIB" >&2 |
| 24 | + exit 1 |
| 25 | +fi |
| 26 | + |
| 27 | +LIB_ABS="$(cd "$(dirname "$LIB")" && pwd)/$(basename "$LIB")" |
| 28 | +SDK_VER="$(xcrun --sdk "$SDK" --show-sdk-version)" |
| 29 | +WORK="$(mktemp -d)" |
| 30 | +trap 'rm -rf "$WORK"' EXIT |
| 31 | + |
| 32 | +# Extract every archive member as a loose object. We deliberately do NOT use |
| 33 | +# `ld -r -force_load <archive>`: the modern linker (ld-prime) localizes *all* |
| 34 | +# symbols of a force-loaded archive, which would strip the `_unienc*` exports |
| 35 | +# too. Passing loose objects makes `-exported_symbols_list` behave as intended. |
| 36 | +( cd "$WORK" && ar x "$LIB_ABS" ) |
| 37 | +member_count="$(ar t "$LIB_ABS" | grep -Ec '\.o$' || true)" |
| 38 | +extracted_count="$(find "$WORK" -maxdepth 1 -name '*.o' | wc -l | tr -d ' ')" |
| 39 | +if [ "$member_count" != "$extracted_count" ]; then |
| 40 | + echo "ERROR: extracted $extracted_count objects but archive lists $member_count (duplicate member names?)" >&2 |
| 41 | + exit 1 |
| 42 | +fi |
| 43 | + |
| 44 | +# Partial link into a single object. |
| 45 | +# -exported_symbols_list : demote every global NOT matching `_unienc*` to a |
| 46 | +# private-extern symbol. |
| 47 | +# -r (without -keep_private_externs) : convert those private-externs (and the |
| 48 | +# ones already produced by `-fvisibility=hidden`) into |
| 49 | +# true local symbols. |
| 50 | +# -platform_version : required by ld-prime even for a `-r` link. |
| 51 | +( cd "$WORK" && xcrun --sdk "$SDK" ld -r -arch "$ARCH" \ |
| 52 | + -platform_version "$PLATFORM" "$MIN_OS" "$SDK_VER" \ |
| 53 | + -exported_symbols_list "$EXPORTS" \ |
| 54 | + *.o -o merged.o ) |
| 55 | + |
| 56 | +rm -f "$LIB_ABS" |
| 57 | +xcrun libtool -static -o "$LIB_ABS" "$WORK/merged.o" |
| 58 | + |
| 59 | +# --- Verify (CI gate; also guards against future linker behaviour changes) --- |
| 60 | +echo "=== exported (global) symbols after localization ===" |
| 61 | +nm -gU "$LIB_ABS" | sort -u |
| 62 | + |
| 63 | +# (a) No mimalloc symbol may remain external or private-external. `nm -gU` lists |
| 64 | +# both (private-externs still coalesce), so it must contain zero of them. |
| 65 | +if nm -gU "$LIB_ABS" | grep -iE '_mi_|_heap_main|_theap_main|mi_unity_'; then |
| 66 | + echo "FAIL: mimalloc symbols are still (private-)external -> would coalesce with Unity" >&2 |
| 67 | + exit 1 |
| 68 | +fi |
| 69 | + |
| 70 | +# (b) FFI entry points must remain global. |
| 71 | +if ! nm -gU "$LIB_ABS" | grep -q '_unienc_UnityPluginLoad'; then |
| 72 | + echo "FAIL: _unienc_UnityPluginLoad is no longer exported" >&2 |
| 73 | + exit 1 |
| 74 | +fi |
| 75 | + |
| 76 | +echo "Localization OK: $(nm -gU "$LIB_ABS" | grep -c '_unienc') unienc symbols exported, 0 mimalloc symbols external" |
0 commit comments