…MPI ranks (#67)
Multi-core analysis in the packaged app runs `mpiexec -n N <bundle>
--_cuflynx-run-analysis ...`, and each rank is a fresh onefile exe that unpacks
its own `_MEIxxxxxx` tree on startup. Into the system `$TMPDIR` by default, so a
full/small `$TMPDIR` becomes an opaque pre-Python rank crash ("Could not create
temporary directory!").
This can't be fixed via `runtime_tmpdir` in the spec: PyInstaller 6.x doesn't
expand `~`/`$VAR` in it on POSIX, and the spec runs on the build machine (a baked
path is the CI runner's home, not the user's). So we relocate at launch time:
when the frozen app re-invokes itself as the runner, `runner_launch_env()` sets
`TMPDIR`/`TMP`/`TEMP` to a roomy per-build user-cache dir
(`<cache>/CUFLynx/onefile-cache/<key>`, key = hash of exe path+size+mtime), moving
every rank's extraction off the volatile system temp. Best-effort: if the cache
dir can't be created the env is left untouched.
Scope: this relocates, it does not de-duplicate — each rank still extracts its own
copy, just under the cache dir. An earlier revision also set PyInstaller's
`_MEIPASS2` "already unpacked" signal to make the ranks share one extraction, but
testing a real onefile build proved that's a no-op on 6.x: the bootloader has no
`_MEIPASS2` (renamed to the internal `_PYI_APPLICATION_HOME_DIR` /
`_PYI_PARENT_PROCESS_LEVEL` protocol), and independent mpiexec ranks can't be
pointed at a shared extraction from the environment. Dropped it. Real sharing would
need a different approach (e.g. a onedir analysis build) — noted as a follow-up.
Pure helpers (`user_cache_base`, `extraction_cache_key`, `extraction_cache_dir`,
`runner_launch_env`) are unit-tested; the frozen relocation itself needs a CI
frozen build to validate (see packaging/README.md).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fixes the multi-core packaging crash in issue #67, rescoped to what actually
works on the shipped PyInstaller 6.x after real-build testing (see thread).
Problem
A multi-core analysis in the packaged app runs
mpiexec -n N <bundle> --_cuflynx-run-analysis .... Each rank is a fresh onefileexe that unpacks its own
_MEIxxxxxxtree on startup, into the system$TMPDIRbydefault. A full/small
$TMPDIR(HPC login nodes, containers, locked-down/tmp)becomes an opaque crash before any Python runs:
[PYI-...:ERROR] Could not create temporary directory!.Fix — relocate the extraction off the system temp
runtime_tmpdirin the spec can't do it (6.x doesn't expand~/$VARon POSIX,and the spec bakes the build machine's path). So at launch time, when the frozen
app re-invokes itself as the runner,
runner_launch_env()setsTMPDIR/TMP/TEMPto a roomy per-build user-cache dir<user-cache>/CUFLynx/onefile-cache/<key>(key = hash of exe path+size+mtime).Every rank then extracts there instead of a volatile
$TMPDIR. Best-effort: if thecache dir can't be created, the environment is left untouched (no regression). For
an external interpreter it's skipped entirely.
Scope — relocation, not de-duplication
Each rank still extracts its own copy; this moves where, not how many. The
first cut of this PR also tried to make the ranks share one extraction via
PyInstaller's
_MEIPASS2signal — I tested that against a real onefile build andit's a no-op on PyInstaller 6.x (the shipped toolchain):
_MEIPASS2(stringsconfirms); parent→childreuse was rewritten as the internal
_PYI_APPLICATION_HOME_DIR/_PYI_PARENT_PROCESS_LEVELprotocol;mpiexecranks at a live parent extraction via those vars(levels 0/1/2) still produced N distinct
_MEIxxxxxxdirs.So
_MEIPASS2is dropped. Real de-duplication would need a different approach(e.g. a onedir analysis build) — left as a follow-up on #67.
Tests
apps/api/tests/test_runtime_paths.py— path/key helpers +runner_launch_envenv construction (36 passed). Asserts the relocation vars are set for the bundle,
skipped for an external interpreter and from source,
_MEIPASS2is not set,and an uncreatable cache leaves the env untouched.
(documented in
packaging/README.md); the destructive_MEIPASS2claim was therisky part and it's gone.
🤖 Generated with Claude Code