ludic bundle: app env "K=V" - the environment Launch Services starts the app with (LSEnvironment)
A switch a library reads only as a process starts - libmalloc's MallocLargeCache, which on a game keeps ~200-300 MB of freed load buffers - has to be in the environment before main. For a .app started from Finder, the Dock or `open` that is Info.plist's LSEnvironment; `app env` is repeatable and each K=V becomes a string in it. bundle_case's probe app carries one and checks it with plutil. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
9f94be7cca
commit
3254d8e81e
2 changed files with 24 additions and 0 deletions
|
|
@ -26,6 +26,7 @@
|
|||
# app category "public.app-category.adventure-games"
|
||||
# app copyright "(c) 2026 Workshopsoft"
|
||||
# app min_macos "12.0"
|
||||
# app env "MallocLargeCache=0" (repeatable: LSEnvironment, what Launch Services starts it with)
|
||||
#
|
||||
# Only `app name` is really needed; everything else has a defensible default
|
||||
# derived from the manifest.
|
||||
|
|
@ -187,6 +188,7 @@ function info_plist(m: Manifest, exe: pointer, has_icon: bool) -> pointer {
|
|||
# A game renders at the display's real resolution; without this the window is
|
||||
# upscaled from 1x and everything drawn in it is soft on any Retina screen.
|
||||
s = s + plist_bool("NSHighResolutionCapable", true)
|
||||
s = s + plist_env(m)
|
||||
s = s + "</dict>" + nl()
|
||||
s = s + "</plist>" + nl()
|
||||
return s
|
||||
|
|
@ -204,6 +206,24 @@ function plist_str(k: pointer, v: pointer) -> pointer {
|
|||
return ` <key>{k}</key>` + nl() + ` <string>{xml_escape(v)}</string>` + nl()
|
||||
}
|
||||
|
||||
# every `app env "K=V"`: the environment Launch Services starts the app with (Finder, `open`, the
|
||||
# Dock) - a switch a library reads only as a process starts, such as libmalloc's MallocLargeCache
|
||||
function plist_env(m: Manifest) -> pointer {
|
||||
var body = ""
|
||||
var i = 0
|
||||
while i + 1 < len(m.app) {
|
||||
if m.app[i] == "env" {
|
||||
let kv = m.app[i + 1]
|
||||
var eq = 0
|
||||
while eq < len(kv) and kv[eq] != '=' { eq += 1 }
|
||||
if eq > 0 and eq < len(kv) { body = body + plist_str(kv[0..eq], kv[eq + 1..len(kv)]) }
|
||||
}
|
||||
i += 2
|
||||
}
|
||||
if body == "" { return "" }
|
||||
return " <key>LSEnvironment</key>" + nl() + " <dict>" + nl() + body + " </dict>" + nl()
|
||||
}
|
||||
|
||||
function plist_bool(k: pointer, v: bool) -> pointer {
|
||||
var t = "<false/>"
|
||||
if v { t = "<true/>" }
|
||||
|
|
|
|||
|
|
@ -370,6 +370,9 @@ function bundle_case() -> void {
|
|||
# the identifier is derived from the package path when the manifest omits it
|
||||
let id = capture_line(`plutil -extract CFBundleIdentifier raw "{app}/Contents/Info.plist" 2>/dev/null`)
|
||||
if id != "io.workshopsoft.probe-app" { bad2(lbl, `bundle id came out [{id}]`); return }
|
||||
# `app env` is what Launch Services starts it with (a Finder or `open` start)
|
||||
let env = capture_line(`plutil -extract LSEnvironment.MallocLargeCache raw "{app}/Contents/Info.plist" 2>/dev/null`)
|
||||
if env != "0" { bad2(lbl, `LSEnvironment.MallocLargeCache came out [{env}]`); return }
|
||||
if not shq(`codesign --verify "{app}" > /dev/null 2>&1`) { bad2(lbl, "the signature does not verify"); return }
|
||||
# and it runs from a directory with none of its assets, reading them from the pack
|
||||
let got = s_trim(capture(`cd / && "{app}/Contents/MacOS/Probe App" 2>&1`))
|
||||
|
|
@ -388,6 +391,7 @@ function bundle_manifest_src() -> pointer {
|
|||
s = s + "app name \"Probe App\"" + nl()
|
||||
s = s + "app icon \"assets/icon.png\"" + nl()
|
||||
s = s + "app copyright \"(c) 2026 A & B\"" + nl()
|
||||
s = s + "app env \"MallocLargeCache=0\"" + nl()
|
||||
s = s + "pack \"assets\"" + nl()
|
||||
return s
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue