如何将Python源码打包为独立二进制包?
bin/lib Structure Got it, let's walk through how to package your entire src folder (including multiple Python scripts and non-code resources like input/output files, docs) into a binary bundle with the clean bin/lib structure you've noticed other developers using. I'll cover the two most reliable tools for this: PyInstaller (great for flexibility) and cx_Freeze (ideal for standardizing the bin/lib layout).
First: Organize Your Project Structure
First, make sure your src folder has a clear structure to avoid headaches during packaging. A typical setup might look like this:
src/ ├── main.py # Your primary entry point script ├── utils/ # Subfolder with helper modules │ └── helper.py ├── data/ # Input templates, configs, etc. │ └── input.csv ├── docs/ # Documentation files │ └── README.md └── outputs/ # Empty folder for runtime output
Option 1: Use PyInstaller (Flexible, Widely Used)
PyInstaller excels at bundling Python apps into binaries, and you can tweak it to output a bin/lib structure.
Step 1: Install PyInstaller
pip install pyinstaller
Step 2: Generate a Spec File
A spec file lets you customize exactly what gets packaged and where it goes. Generate one for your main entry point:
pyinstaller --name my_app src/main.py
This creates a my_app.spec file in your project root.
Step 3: Customize the Spec File
Open my_app.spec and modify it to:
- Include all your non-code resources (data, docs, outputs)
- Define the
bin/liboutput structure
Here's a modified spec file example:
# my_app.spec block_cipher = None a = Analysis( ['src/main.py'], pathex=['./src'], binaries=[], # Add your non-code resources here: (source_path, destination_path) datas=[ ('src/data', 'data'), ('src/docs', 'docs'), ('src/outputs', 'outputs'), # Add any other subfolders from src you need to include ], hiddenimports=[], # Add modules that are dynamically imported (if any) hookspath=[], hooksconfig={}, runtime_hooks=[], excludes=[], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, noarchive=False, ) pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) exe = EXE( pyz, a.scripts, [], exclude_binaries=True, name='my_app', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, console=True, # Set to False for GUI apps on Windows disable_windowed_traceback=False, target_arch=None, codesign_identity=None, entitlements_file=None, ) coll = COLLECT( exe, a.binaries, a.zipfiles, a.datas, strip=False, upx=True, upx_exclude=[], name='my_app_lib', # This will be your lib folder content )
Step 4: Build the Bundle with bin/lib Structure
Run PyInstaller with the spec file, then rearrange the output to match the structure:
pyinstaller my_app.spec
This generates a dist/my_app_lib folder (all dependencies/resources) and a standalone my_app executable. Now just organize them into your desired structure:
# Create bin and lib folders mkdir -p dist/bin dist/lib # Move the executable to bin mv dist/my_app dist/bin/ # Move the dependency folder to lib mv dist/my_app_lib dist/lib/
Option 2: Use cx_Freeze (Built-in bin/lib Support)
cx_Freeze is designed to produce standard package structures, making it perfect if you want bin/lib out of the box.
Step 1: Install cx_Freeze
pip install cx_Freeze
Step 2: Create a setup.py
Create this file in your project root to define the packaging configuration:
# setup.py import os import sys from cx_Freeze import setup, Executable # Define your main entry point main_script = os.path.join("src", "main.py") target = Executable( script=main_script, base=None, # Use "Win32GUI" for Windows GUI apps target_name="my_app" # Name of the final executable ) # List all non-code resources to include (source -> destination) include_files = [ (os.path.join("src", "data"), "data"), (os.path.join("src", "docs"), "docs"), (os.path.join("src", "outputs"), "outputs"), ] setup( name="my_app", version="1.0", description="My Python Application", executables=[target], options={ "build_exe": { "include_files": include_files, "build_exe": os.path.join("dist", "lib", "my_app"), # Dependencies go here "bin_path": os.path.join("dist", "bin") # Executable goes here } } )
Step 3: Build the Bundle
Run the setup script to generate your bin/lib structure automatically:
python setup.py build
You'll find your executable in dist/bin/my_app and all dependencies/resources in dist/lib/my_app.
Critical Tips for Success
- Handle Resource Paths Correctly: In your Python code, use a helper function to find resources both in development and after packaging. For example:
import os import sys def get_resource_path(relative_path): # Get path to resources (works in dev and packaged mode) if hasattr(sys, '_MEIPASS'): # PyInstaller's temporary runtime path return os.path.join(sys._MEIPASS, relative_path) # Development mode: relative to this script's folder return os.path.join(os.path.dirname(os.path.abspath(__file__)), relative_path) # Usage example input_file = get_resource_path("data/input.csv") - Dynamic Imports: If your code uses
importlibor dynamic imports, add those modules tohiddenimports(PyInstaller) orpackages(cx_Freeze) to ensure they're included. - Cross-Platform Packaging: You can't package for Windows on Linux (or vice versa) easily—run the packaging command on the target OS to get a working binary.
内容的提问来源于stack exchange,提问作者aBiologist

