# study-build-python-whl **Repository Path**: Silfra/study-build-python-whl ## Basic Information - **Project Name**: study-build-python-whl - **Description**: 学习如何将 python 项目代码打包为 whl 文件 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2025-01-21 - **Last Updated**: 2025-08-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 将项目打包为 `whl` 文件并安装 ### 环境搭建 **Python 虚拟环境:** 本项目对 python 的版本没有必然要求,但最好是 3 版本,本项目使用 python 3.12 版本。 ```bash python -m venv .venv ``` 激活并安装需要依赖(激活虚拟环境在此省略): ```bash pip install setuptools wheel ``` **操作系统:** 本项目构建时使用 Windows 10 操作系统。 ### 建立项目结构 新建一些文件和文件夹,搭建项目框架,搭建好的目录树如下: ``` 📁 项目根目录 ├── 📄 LICENSE ├── 📂 mypackage │ ├── 📄 cli.py │ └── 📄 __init__.py ├── 📄 README.md └── 📄 setup.py ``` ### 写入文件内容 如下写入文件内容: `LICENSE` : ``` MIT License ``` `cli.py` : ```python import argparse def main(): parser = argparse.ArgumentParser(description="MyPackage CLI Example") parser.add_argument("name", type=str, help="Your name") args = parser.parse_args() print(f"Hello, {args.name}! Welcome to MyPackage CLI.") ``` `__init__.py` : ```python __version__ = "0.1.0" ``` `README.md` : ```markdown # MyPackage A Python package example with a CLI tool. ``` `setup.py` : ```python from setuptools import setup, find_packages setup( name="mypackage", version="0.1.0", description="A Python package with a CLI tool", long_description=open("README.md", encoding="utf-8").read(), long_description_content_type="text/markdown", author="Your Name", author_email="your.email@example.com", url="https://github.com/yourusername/mypackage", license="MIT", packages=find_packages(), python_requires=">=3.6", classifiers=[ "Programming Language :: Python :: 3", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", ], entry_points={ "console_scripts": [ "mypackage-cli=mypackage.cli:main", ], }, ) ``` ### 构建 `whl` 文件 使用指令 `python setup.py bdist_wheel` 构建 `whl` 文件,运行后,会在当前目录下生成 `build` 、 `dist` 和 `mypackage.egg-info` 目录,且内容如下: ``` 📁 项目根目录 ├── 📂 build │ ├── 📂 bdist.win-amd64 │ └── 📂 lib │ └── 📂 mypackage │ ├── 📄 cli.py │ └── 📄 __init__.py ├── 📂 dist │ └── 📄 mypackage-0.1.0-py3-none-any.whl ├── 📂 mypackage.egg-info │ ├── 📄 dependency_links.txt │ ├── 📄 entry_points.txt │ ├── 📄 PKG-INFO │ ├── 📄 SOURCES.txt │ └── 📄 top_level.txt ``` **解释:** - ★ `build/lib` 目录下的 `mypackage` 目录中的内容和原本项目中的 `mypackage` 目录下的内容完全相同,是从项目目录中复制过来的, `build` 目录中用于存放构建 `whl` 文件时产生的临时文件。 - `dist` 目录下存放构建好的 `whl` 文件。 - `mypackage.egg-info` 目录下存放构建 `whl` 文件的元数据等。 ### 安装 `whl` 包 构建好 `whl` 文件后,使用 `pip` 直接安装该包: ```bash pip install dist/mypackage-0.1.0-py3-none-any.whl ``` 安装完成后,会在虚拟环境目录下( `.venv` )的 `Lib/site-packages` 目录下生成 `mypackage` 和 `mypackage-0.1.0.dist-info` 目录,其中, `mypackage` 目录下的内容也是从 `whl` 文件中直接解压到的,和原本项目中的 `mypackage` 目录内容完全相同。 > 因此,可以理解为,原项目中的 `mypackage` 目录和未来要安装到环境中的 `pip` 包的内容完全相同。 同时,会在虚拟环境目录下的 `Scripts` 目录下生成一个 `mypackage-cli.exe` 文件。 **解释:** 该二进制文件是在 `setup.py` 文件中定义的,在 `entry_points` 中的 `console_scripts` : ```python entry_points={ "console_scripts": [ "mypackage-cli=mypackage.cli:main", ], }, ``` > 当在 `setup.py` 中没有定义 `entry_points` 时,安装 `whl` 后不会在 `Scripts` 目录下生成任何文件。 其中,第一个 `mypackage-cli` 为未来生成的二进制文件的名称,即 `mypackage-cli.exe` ,同时也代表可在虚拟环境终端中使用的 `mypackage-cli` 指令,等号后面的 `mypackage.cli` 代表 `mypackage/cli.py` 路径和文件,其中的点" `.` "代表文件路径分隔符,最后一个 `cli` 表示最终的 `py` 文件,即 `cli.py` ,冒号后面的 `main` 代表 `main()` 函数,即 `cli.py` 中定义的 `main()` 函数。 当 `whl` 文件被安装到虚拟环境中时,上述的二进制文件会被生成到 `Scripts` 目录中,也就注册到了虚拟环境的终端中,在终端中可以使用 `mypackage-cli` 指令。当使用 `mypackage-cli` 指令时,相当于执行**虚拟环境**中的 `mypackage/cli.py` 文件中的 `main()` 函数,可以看到 `main()` 函数接收一个参数,并在控制台打印相应数据,因此执行 `mypackage-cli John` 的效果如下: ```bash $ mypackage-cli John Hello, John! Welcome to MyPackage CLI. ``` 以上就完成了一个包含命令行的简单的 `whl` 包的构建和安装。