Python / Compiling Code and Creating EXE Files
To distribute Python code as a Windows EXE, PyInstaller can bundle your program with the Python runtime and required libraries. A .pyc created by py_compile is Python bytecode, not a standalone Windows executable. Verify a folder bundle first, then switch to a single executable if needed to make problems easier to isolate.
Bytecode compilation versus executable bundling
py_compile turns source into bytecode files. PyInstaller bundling collects the interpreter and dependencies into a distributable application. This differs from translating an ordinary Python program into optimized native machine code through C. Bundling does not automatically improve execution speed or securely conceal your source.
Output depends on the operating system and architecture. Build Windows EXEs on Windows; PyInstaller is not a cross-compiler that produces them on Linux through a single option. Check the supported environments and your packages’ compatibility.
Prepare a Windows project and virtual environment
Use PowerShell on Windows with Python 3 and pip installed. Create a new working folder, open a terminal there, and run these commands in order. If py -3 is unavailable, replace it in the first line with the installed Python executable’s path or a python command pointing to that interpreter.
py -3 -m venv .venv
.\.venv\Scripts\python.exe -m pip install "pyinstaller==6.22.3"
.\.venv\Scripts\python.exe -m PyInstaller --version
.venv is the project’s virtual environment. Subsequent commands call its Python directly, so neither script activation nor PowerShell execution-policy changes are necessary. Version 6.22.3 pins the example’s PyInstaller behavior; check compatibility and options again if using another release. Verify that installation succeeds and the last command prints 6.22.3.
Install any dependencies your application actually uses into this same environment. Building from a global environment containing many unrelated packages can complicate analysis and management of the result.
Save a complete example and generate bytecode
Create hello.py in UTF-8 in the working folder:
print("Hello, packaging!")
Hello, packaging!
Run the source first; it should print the message shown above.
.\.venv\Scripts\python.exe hello.py
To try bytecode compilation alone, run:
.\.venv\Scripts\python.exe -m py_compile hello.py
Success normally produces no output and creates a file such as hello.cpython-312.pyc in __pycache__. Its version marker depends on Python. Renaming it to EXE does not make it standalone; bytecode still needs a compatible Python runtime.
Build and distribute a folder bundle
Run these two commands from the working folder, executing the second only after the build succeeds.
.\.venv\Scripts\python.exe -m PyInstaller --onedir --name hello-folder hello.py
.\dist\hello-folder\hello-folder.exe
The result is Hello, packaging!. Distribute the entire dist\hello-folder folder, which contains the executable and support files. Copying the EXE alone can leave required libraries behind. Support files may appear under _internal; the exact layout depends on packages and options.
build contains intermediate and diagnostic files; hello-folder.spec records build settings. Users receive the distribution under dist, rather than your build or .venv folders. See the PyInstaller usage reference for option details.
Create a single executable
Once the folder build works, bundle the same source as one file. A different name keeps both results available for comparison.
.\.venv\Scripts\python.exe -m PyInstaller --onefile --name hello-single hello.py
.\dist\hello-single.exe
You can distribute dist\hello-single.exe as one file; its output is unchanged. Single-file bundles extract internal files to a temporary location when starting, which can increase startup time. Compare actual applications rather than assuming guaranteed size or speed advantages.
Do not add --windowed to this console example. That option may suit GUI applications without a console, but applying it indiscriminately to print() or input() programs makes input, output, and diagnosis harder. Treat the underlying failure rather than making administrator execution or disabling security software the default solution.
The folder and single-file examples were built and their output checked on Windows with Python 3.12.14 and PyInstaller 6.22.3. These checks cover console examples on the same host; they do not establish behavior on a separate PC without Python or in a GUI application.
Include text, images, and other data files
Do not assume that every file read by your code is collected automatically. Save a UTF-8 file named message.txt containing the single line Hello from bundled data!. Create hello_data.py beside it with this complete source:
from pathlib import Path
message = Path(__file__).resolve().with_name("message.txt")
print(message.read_text(encoding="utf-8").strip())
Hello from bundled data!
Running the source and the following bundle should produce the same message. A path based on __file__ does not depend on the terminal’s current folder and can locate files inside the bundle.
.\.venv\Scripts\python.exe -m PyInstaller --onefile --name hello-data --add-data "message.txt:." hello_data.py
.\dist\hello-data.exe
--add-data "message.txt:." includes the file at the bundle’s top level. The current documented separator is a colon; avoid mixing in older platform-specific separator examples. Match code paths to the data inclusion rules for images and configuration too. Changes to data extracted from a single-file executable are not persistent storage; save user settings and results in a separate writable user location.
Diagnose failures and check before distribution
- If the EXE closes immediately, run it from PowerShell instead of double-clicking it to read the error. Confirm that the source works in the same virtual environment.
- For missing modules, inspect the environment’s installations and how imports occur. Dynamic imports can need extra collection settings. Read
build\name\warn-name.txt, recognizing that not every warning is fatal. - For missing data, compare the destination in
--add-datawith the code path. Return to a folder bundle to inspect files and narrow down the failure. - Test actual features on the target operating system and architecture. Include a separate environment without Python, file access, external program dependencies, and redistribution terms for included packages.
Consult PyInstaller troubleshooting for diagnostic methods. Keep build and execution commands distinct, and record the reproducing source, package versions, and error messages to make the cause easier to identify.




