Skip to content

iOS release: scratch removed on every exit (MOB-425); release dead-strips + plugin no-dead-strip link check (MOB-471) - #136

Merged
GenericJam merged 2 commits into
masterfrom
mob-425-471-release-scratch-deadstrip
Oct 13, 2026
Merged

GenericJam merged 2 commits into
masterfrom
mob-425-471-release-scratch-deadstrip

Conversation

@GenericJam

Copy link
Copy Markdown
Owner

Fixes MOB-425 and MOB-471.

MOB-425: mix mob.release --ios no longer leaks its scratch (~100 MB a run)

release_device.sh used bare mktemp -d (macOS ignores TMPDIR) for BUILD_DIR (never removed), the exqlite objects and the IPA staging dir (removed on success only), plus /tmp/actool_*.plist. Release.build_ipa/1 now runs the script inside NativeBuild.with_temp_build_dir("release", …) (the MOB-313 helper, removed in after) and passes the dir as MOB_RELEASE_BUILD_DIR; every scratch path is under it (Release.release_scratch_sh/0). A direct run of the script makes its own dir under $TMPDIR and removes it with an EXIT trap. MOB-313's decision record notes that release now follows it.

MOB-471: release link dead-strips; plugin archives get a no-dead-strip undefined-symbol check

  • The release swiftc link passes -Xlinker -dead_strip, as mob_new's ios/build.zig / build_device.zig do. A test asserts the release script and both templates agree.
  • MobDev.Plugin.IosLinkCheck runs after every iOS (:ios_sim, :ios_device) cpp_archive build in build_plugin_static_archives/4 (sim build, device build, release): it links the archive into a throwaway dylib without -dead_strip and fails the build on any unresolved symbol that the target's ERTS libs, mob core's iOS sources or the iOS SDK's .tbd stubs don't define, naming the plugin, symbols and referencing members. Allow-list derived from those inputs; the SDK is in whole because mob core autolinks frameworks (mob_scene3d's Filament needs OpenGL ES, which no manifest declares).
  • Decision record: decisions/2026-10-13-ios-release-dead-strips-and-plugin-link-check.md.

Verification (Mac mini, 2026-10-13)

  • Blank host (mix mob.new --ios) + default plugins + mob_whisper 0.1.2 + mob_scene3d 0.2.0:
    • hex mob_dev 0.7.23: mix mob.release --ios left $DARWIN_USER_TEMP_DIR/tmp.jP1HXE0aDY (108 MB).
    • this branch: release succeeds; no new tmp.*/mob_release* dir in DARWIN_USER_TEMP_DIR, TMPDIR or /tmp; same with a forced failure (bogus ios_dist_profile_uuid, fails after link + bundle at the profile step).
    • app binary in the .ipa 14,437,328 → 12,631,520 bytes (−12.5 %); .ipa 54,319,714 → 53,581,889 bytes.
    • mix mob.deploy --native --ios on iPhone 18 Pro sim (iOS 27) + mix mob.selftest: 4 passed, 0 failed, 2 skipped (location: no selftest; biometric: nothing enrolled).
  • The check on mob_whisper 0.1.1's archive (the MOB-470 version) reports exactly dl_get_sym, dl_load_library, dl_error from ggml-backend-reg.o; 0.1.2 and mob_scene3d pass (~0.5 s each).
  • mix test (full, macOS): 3054 passed. New tests: test/mob_dev/release_scratch_test.exs (runs the prologue with a fake TMPDIR, success and failure, and with MOB_RELEASE_BUILD_DIR), test/mob_dev/plugin/ios_link_check_test.exs (:macos_only fixture archives: MOB-470 shape fails, links with -dead_strip and not without; clean one passes; mob-core symbols only allowed with the mob checkout).

Remaining in the user temp dir after a release, not ours: actool's ibtoold FIFOs and an empty TemporaryDirectory.* (Xcode; actool ignores TMPDIR for these).

Review: see comments.

…ad-strips, plugin archives get a no-dead-strip undefined-symbol check (MOB-471)

MOB-425: release_device.sh wrote ~100 MB of scratch with bare mktemp -d
(ignores TMPDIR) and never removed BUILD_DIR. build_ipa/1 now runs it in
NativeBuild.with_temp_build_dir/2 (MOB_RELEASE_BUILD_DIR); every scratch path
is under it; a direct run makes its own under TMPDIR with an EXIT trap.

MOB-471: the release link passes -Xlinker -dead_strip like mob_new's dev
links. MobDev.Plugin.IosLinkCheck links each iOS cpp_archive plugin archive
without -dead_strip and fails the build on any symbol the BEAM, mob core or
the iOS SDK don't define (the MOB-470 class).
@GenericJam

Copy link
Copy Markdown
Owner Author

Review: reviewer subagent (Codex rate-limited until 6:25 PM today): MERGE.

Round 1 (6822636): no blocking findings. Should-fix: mix mob.release passed an unexpanded mob_dir to the link check (~ paths would drop mob core's symbols, release only). Nitpicks: {_, 0} = matches on xcrun/nm would crash instead of erroring; tests cover the prologue, not the whole script (left: repo forbids source-text tests; the smoke covers it); a mktemp/TMPDIR doc claim (withdrawn: /usr/bin/mktemp -d does ignore TMPDIR here; the reviewer had hit a shell builtin). The reviewer diffed old vs new generated scripts: byte-identical apart from the intended changes.
Fixed in f53cdb1 (expand mob_dir; every xcrun/nm failure is {:error, msg}; SDK path from the last output line).
Round 2 (f53cdb1): MERGE, no findings. Known, documented gap: any SDK export is accepted, so a dead-code reference to a framework the app doesn't link still passes (reproduced with Accelerate's vDSP_fft_zip), listed under "Not covered" in the decision record.

CI on f53cdb1: green (run 38460310349).

@GenericJam
GenericJam merged commit 6efa92b into master Oct 13, 2026
6 checks passed
@GenericJam
GenericJam deleted the mob-425-471-release-scratch-deadstrip branch October 13, 2026 20:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant