Basically, here’s how pdeploy works internally:
On runtime.panda3d.org where all of the plugin packages are hosted, there is also a “p3dembed” package, which has a “p3dembed” executable for every platform out there. This is basically a modified version of the Panda3D runtime “panda3d” executable, except it works a little differently:
- It defines a const volatile 32-bits unsigned integer, that is initially set to 0xFF3D3D00.
- It reads this variable, assumes that it is an offset in the file pointing to a block of metadata followed by the .p3d data, and starts running the .p3d at that location in the file.
This p3dembed executable is useless in its current form, since the variable contains a meaningless marker, 0xFF3D3D00. Running it will make it crash, since no .p3d data exists at that offset (actually, it checks for the marker and will cleanly exit with a friendly error, but that’s just an implementation detail.)
Now, when you run pdeploy, it downloads all of these versions of p3dembed. It then tacks appropriate metadata followed by the .p3d data onto the end of the executable. Then, it scans the executable code for the 0xFF3D3D00 marker, and replaces it with the actual offset of the .p3d data (which in this case, is equal to the size of the original p3dembed file), so that next time you run the executable, the variable will contain the actual offset instead of the marker.
So when you run this new executable, it’ll know exactly the offset of the .p3d data in the executable file, and it will start running the .p3d file at that offset.
For more information, you can consult the source code at direct/src/plugin_standalone/ (for p3dembed) or direct/src/p3d/DeploymentTools.py (for pdeploy). Or feel free to ask me more questions about it.
It shouldn’t be difficult to do the same for raw Python. Since Python bytecode is platform-independent, all you need to make is a wrapper executable that runs (using the Python C API) whatever archive of bytecode is tacked onto the end of the executable, statically link it with the CPython ABI, and compile it for every platform.
I bet that the existing tools like py2exe and pyinstaller use a similar approach. I think that py2exe uses a zip file with bytecode files attached. (Python can implicitly read py/pyc/pyo from zip files, I believe).
If you need any help, let me know.