Skip to content

包与发布

本章讲解Cython项目的打包和发布。好的打包策略能让Cython模块跨平台使用,触达更多用户。

学习路径:包结构 → 跨平台构建 → wheel打包 → 版本管理

核心工具:

  • setuptools:Python打包标准
  • CI/CD:自动化构建测试
  • manylinux:跨Linux发行版兼容

功能说明:标准Python包目录结构。

mypackage/
├── mypackage/
│ ├── __init__.py
│ ├── core.pyx
│ ├── utils.pyx
│ └── utils.html # cython -a生成的HTML
├── tests/
│ ├── test_core.py
│ └── test_utils.py
├── setup.py
├── README.md
└── LICENSE

说明:

  • 内层mypackage/是源代码目录
  • 外层是项目根目录
  • tests/放置测试代码

功能说明:在__init__.py中导出公共接口。

mypackage/__init__.py
from mypackage.core import MyClass
from mypackage.utils import fast_function
__all__ = ["MyClass", "fast_function"]

功能说明:版本信息统一管理。

mypackage/__init__.py
__version__ = "1.0.0"

功能说明:Windows平台使用MSVC编译器。

setup.py
from setuptools import setup, Extension
from Cython.Build import cythonize
import sys
if sys.platform == "win32":
ext_modules = cythonize([
Extension("mypackage.core", ["mypackage/core.pyx"]),
], compiler_directives={"msvc": True})
else:
ext_modules = cythonize("mypackage/*.pyx")

功能说明:macOS使用clang,支持动态库。

# macOS特定配置
ext_modules = [
Extension("mypackage.core",
["mypackage/core.pyx"],
extra_link_args=["-dynamiclib"],
)
]

功能说明:Linux使用gcc,启用-fPIC位置无关代码。

# Linux构建
ext_modules = [
Extension("mypackage.core",
["mypackage/core.pyx"],
extra_compile_args=["-fPIC"],
)
]

功能说明:GitHub Actions自动构建多平台wheel。

.github/workflows/build.yml
name: Build
on: [push, pull_request]
jobs:
build:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: [3.9, "3.10", "3.11"]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: pip install cython numpy
- name: Build
run: python setup.py build_ext --inplace

功能说明:wheel中不包含cython -a生成的HTML文件。

setup.py
from setuptools import setup
from Cython.Build import cythonize
import shutil
extensions = [
Extension("mypackage.core", ["mypackage/core.pyx"]),
]
setup(
name="mypackage",
version="1.0.0",
ext_modules=cythonize(extensions),
cmdclass={"build_ext": shutil.ignore_patterns("*.html")},
)

功能说明:构建并上传wheel到PyPI。

Terminal window
# 构建wheel
python -m build wheel
# 上传到PyPI
twine upload dist/mypackage-1.0.0-*.whl

输出示例:

dist/
├── mypackage-1.0.0-cp39-cp39-linux_x86_64.whl
├── mypackage-1.0.0-cp39-cp39-macosx_x86_64.whl
└── mypackage-1.0.0-cp39-cp39-win_amd64.whl

功能说明:遵循语义化版本规范。

__version__ = "1.2.3" # 主版本.次版本.修订
# 主版本:不兼容的API变更
# 次版本:向后兼容的功能添加
# 修订:向后兼容的bug修复

功能说明:保持向后兼容的API设计。

# 保持向后兼容
cpdef int old_function(int x) except -1:
# 旧函数保持
return x * 2
cpdef int new_function(int x, int y=1) except -1:
# 新函数有默认值参数,调用更便捷
return x * y

最佳实践:

  • 不删除旧函数,标记为deprecated
  • 新函数添加默认参数减少破坏性
  • 重大版本才进行不兼容变更

平台编译器特殊配置
Windowsmsvccompiler_directives={"msvc": True}
macOSclangextra_link_args=["-dynamiclib"]
Linuxgccextra_compile_args=["-fPIC"]
跨平台-CI/CD多平台矩阵
  1. 使用语义化版本(major.minor.patch)
  2. 跨平台用CI/CD自动化构建
  3. wheel打包避免包含.html文件
  4. 保持API向后兼容

  1. 创建完整的包结构(含__init__.py和多个模块)
  2. 配置多平台CI/CD(GitHub Actions)
  3. 构建wheel包并使用twine上传到TestPyPI
  4. 实现版本管理,导出__version__
  5. 设计保持向后兼容的API(添加新参数时使用默认值)
  6. 配置manylinux环境构建兼容多个Linux发行版的wheel