Speed up building multiple executable with onedir
#8137
|
Hi all, first of all thank you so much for building and maintaining this open source library. I have an application which is composed of several tool (entrypoints). All tools share the same dependencies. I already have a spec file for building a So the result is that for each tool I'm actually importing the same packages but the operation is repeated for each tool in either I really like that the binaries' size is just a few KB for each tool while having a single large directory that includes the dependencies. So is there a way to create the directory of the bundle only once? Should I run the the I've found the discussions #6634 and #7140 but they all seem to suffer from the same slow down of running the analysis for all entrypoints. This is how my spec file looks like: |
Replies: 2 comments 3 replies
There is no officially supported, out-of-the box way for that. If all those entry-points really have identical import dependencies, I suppose you could try running Analyis only once, on one of them, and then re-use the results, while manually creating the But if I were in your place, I would reconsider having multiple executables in the first place, as each of them will contain its copy of PYZ, with all collected modules. For programs with complex dependencies, that alone might unnecessarily baloon the distribution size. I would instead opt for having a single executable whose first argument is |
|
Follow-up: confirmed working approach Reporting back after (after some time) experimenting in building mutliple binaries, with cythonized source code with the Short version: it works. Running a single Minimal snippet: from copy import copy
from pathlib import Path
apps = [
('tool-a', 'app/tools/a.py'),
('tool-b', 'app/tools/b.py'),
('tool-c', 'app/tools/c.py'),
]
# Run Analysis once, on any entry script
a = Analysis(
['app/tools/a.py'],
hiddenimports=hiddenimports,
noarchive=True, # required, see later when creating the EXE
...
)
compiled_apps = []
for name, script in apps:
scripts = copy(a.scripts)
scripts[-1] = (Path(script).stem, script, 'PYSOURCE')
exe = EXE(
PYZ(), # empty. With noarchive=True, no PYZ archive needed
scripts,
exclude_binaries=True,
name=name,
...
)
compiled_apps.extend([a.binaries, a.datas, exe])
coll = COLLECT(*compiled_apps, name='my-bundled-app')The result is a layout like: A few implementation notes:
One caveat worth flagging: the Analysis always runs in full regardless of how many executables you build. If your goal is to speed up iteration on a single component, a component filter (e.g. an env var that limits which Thanks again to rokm for pointing in the right direction. |
Follow-up: confirmed working approach
Reporting back after (after some time) experimenting in building mutliple binaries, with cythonized source code with the
onedirapproach.Short version: it works. Running a single
Analysisand swappinga.scripts[-1]per entrypoint produces a valid onedir bundle where all executables share a single_internal/directory.Minimal snippet: