news 2026/10/14 17:44:33

KLayout PyPI 发布流程详解:从 wheel 到源码包用 twine 上传 KLayout Python 包

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
KLayout PyPI 发布流程详解:从 wheel 到源码包用 twine 上传 KLayout Python 包
  • 硬件开发
  • 桌面应用
  • 图形学

【免费下载链接】klayout

KLayout Main Sources

项目地址:https://gitcode.com/gh_mirrors/kl/klayout
点击查看免费下载

本文以仓库中的 ci-scripts/twine/README.md 为核心,讲清 KLayout 独立 Python 包(klayout,即src/pymod对应的 pymod 发布体系)如何把构建好的 wheel 文件和源码 tarball 上传到 PyPI。读完后你可以完整掌握:本地构建产物如何组织、上传命令及其参数演进(从travis upload到twine upload)、版本号从何而来,以及仓库中 Jenkins / Azure Pipelines 两条自动化发布链路是如何把"构建—测试—上传"串起来的。

一、文档核心流程:先上传 wheel,再上传源码包

ci-scripts/twine/README.md 记录的是当时 KLayout 向 PyPI 发布klayout包的完整手工操作,分为两个阶段。

1. 定位到 wheel 部署目录并上传所有 wheel

构建完成后,产物会集中部署到一个dist-pymod风格的目录中(文档举例为/Users/tlima/Dropbox/Apps/travis-deploy/Builds/klayout/dist-pymod/0.26.0.dev10)。进入该目录后执行:

travis upload *.whl

该命令执行时会提示输入与你的 PyPI 账号关联的 username 和 password(这是travis-pypi-tool时代的交互方式,凭据由工具本地缓存)。*.whl通配符会把该目录下所有平台的 wheel(如 manylinux、win32 等版本)一次性上传。

2. 构建源码 tarball 并上传

wheel 上传成功后,回到 KLayout 的 git 源码目录,执行:

python setup.py sdist

在生成的dist/目录中会找到类似klayout-0.26.0.dev10.tar.gz的源码包,然后执行:

travis upload klayout-0.26.0.dev10.tar.gz

这样就完成了"wheel + sdist"两类产物的 PyPI 发布。文档中示例版本号0.26.0.dev10是当时开发版的命名;当前仓库 version.sh 中的中央版本配置为:

KLAYOUT_VERSION="0.30.12" # The version used for PyPI (don't use variables here!) KLAYOUT_PYPI_VERSION="0.30.12"

setup.py sdist生成的包名版本正是读取KLAYOUT_PYPI_VERSION——setup.py 中Config.version()用正则从version.sh提取该值,并作为setup(name=config.root, version=config.version(), ...)的参数传入。因此手工上传前应先确认version.sh中的KLAYOUT_PYPI_VERSION是目标发布版本,否则 tarball 文件名(例如klayout-0.30.12.tar.gz)会与预期不符。

3. 源码包内容如何界定

setup.py sdist打进去哪些文件,由 MANIFEST.in 决定。当前清单递归收录了各模块的*.cc、*.h、pysetup.toml(如src/pymod、src/pya/pya、src/tl/tl等)、数据库插件源码(src/plugins/*/db_plugin)以及version.sh和src/py.typed。这保证了从 PyPI 下载 sdist 的用户能在有编译器环境下重建整个klayoutPython 包。

二、产物从哪里来:wheelhouse 与 setup.py 构建

文档中"travis-deploy 目录下的 wheel"并非凭空产生。从仓库的构建脚本看,产物的标准落地位置是wheelhouse/目录:

ci-scripts/docker/docker_build.sh(manylinux 容器内构建脚本)的核心构建与验证步骤:

# Compile wheel and build source distribution cd /io "/opt/python/$PY_VERSION/bin/python" setup.py bdist_wheel -d /io/wheelhouse/ || exit 1 "/opt/python/$PY_VERSION/bin/python" setup.py sdist --formats=zip -d /io/wheelhouse || exit 1 # Bundle external shared libraries into the wheels via auditwheel for whl in /io/wheelhouse/*linux_*.whl; do auditwheel repair "$whl" -w /io/wheelhouse/ || exit 1 done # Install packages and test TEST_HOME=/io/testdata "/opt/python/$PY_VERSION/bin/pip" install klayout --no-index -f /io/wheelhouse || exit 1 "/opt/python/$PY_VERSION/bin/python" $TEST_HOME/pymod/import_db.py || exit 1 "/opt/python/$PY_VERSION/bin/python" $TEST_HOME/pymod/import_rdb.py || exit 1 "/opt/python/$PY_VERSION/bin/python" $TEST_HOME/pymod/import_tl.py || exit 1 "/opt/python/$PY_VERSION/bin/python" $TEST_HOME/pymod/pya_tests.py || exit 1

几点值得注意的实现细节(均可在仓库源码中核实):

  • 构建命令是setup.py bdist_wheel/setup.py sdist。setup.py顶部注释解释了 KLayout 共享对象架构对打包的挑战:Python 扩展库(下划线前缀,如_tl、_gsi)依赖一批实现库,distutils 只能用extra_objects方式注入依赖;Linux 上还要用-Wl,-soname去掉路径、-Wl,-rpath,$ORIGIN保证运行期按相对路径查找。这些链接参数在 setup.py 的Config.link_args()中实现。
  • auditwheel repair 是 manylinux 标签的前提:把lib_*(libcurl、libexpat、libz、libpng 等)打进 wheel,使 wheel 获得 manylinux 标签。ci-scripts/docker/README.md 明确说:"This command will generate a wheel and place it inwheelhouse/klayout-*manylinux1*.whl. This is the wheel that needs to be uploaded to PyPI via twine."——这正是 twine 上传文档的产物来源。
  • 上传前自带冒烟测试:构建脚本在安装 wheel 后运行testdata/pymod/下的import_db.py、import_rdb.py、import_tl.py和pya_tests.py,确保上传到 PyPI 的 wheel 至少能导入核心模块。

Jenkins 版本脚本 ci-scripts/docker/docker_build_jenkins.sh 流程相同,只是通过环境变量KLAYOUT_SETUP_MULTICORE=1限制为单核编译,避免压垮 Jenkins 宿主机;而setup.py中读取该变量来决定编译线程数(默认取multiprocessing.cpu_count()),并对CCompiler.compile做了并行编译的 monkey-patch。

三、从 travis upload 到 twine:文档命令在当前仓库中的演进

ci-scripts/twine/README.md 中的travis upload属于 Travis CI 时期的travis-pypi-tool用法。当前仓库的发布链路已改用twine,且凭据不再交互式输入,而是通过 CI 变量注入。两处可直接核实的实现:

1. Jenkins 流水线:Jenkinsfile-pypi

Jenkinsfile-pypi 的完整发布逻辑:

platform = pypi_platform() py_version = pypi_py_version() currentBuild.description = "PyPI deployment " + platform docker_image = "jenkins-manylinux2014_x86_64-pypi" target = platform + ".whl" node("linux") { stage("Checkout sources") { checkout scm } stage("Building target ${target}") { sh("rm -rf wheelhouse ; mkdir -p wheelhouse") withDockerContainer(image: docker_image, args: "-v " + pwd() + ":/io") { sh("PY_VERSION=" + py_version + " /io/ci-scripts/docker/docker_build_jenkins.sh") } } stage("Publish and test") { // publish for release tags if (BRANCH_NAME.startsWith('pypi_')) { sh("twine upload --skip-existing wheelhouse/klayout-*manylinux2014*.whl wheelhouse/*.zip") } } }

对照手工文档可以看到三个关键差异:

手工流程(travis README)Jenkinsfile-pypi(twine)
travis upload *.whltwine upload --skip-existing wheelhouse/klayout-*manylinux2014*.whl wheelhouse/*.zip
python setup.py sdist(tar.gz 落dist/)sdist --formats=zip -d /io/wheelhouse(在容器脚本内完成,产物为.zip,与 wheel 一起上传)
交互式输入 username/password凭据由 Jenkins 凭据系统管理,命令行不再交互
任意时机可执行仅当分支名以pypi_开头(发布专用分支/标签)才上传

--skip-existing参数表示遇到 PyPI 上已存在的同一版本文件时跳过而不是报错,这使得发布任务可安全重跑(PyPI 不允许覆盖已发布版本)。

2. Azure Pipelines:Windows 侧的上传

azure-pipelines.yml 末尾的上传阶段与 Jenkins 版本风格一致,但使用TWINE_*环境变量显式注入凭据:

- bash: | pip install -U twine twine upload --skip-existing $BUILD_ARTIFACTSTAGINGDIRECTORY/* env: TWINE_USERNAME: $(TWINE_USERNAME) TWINE_PASSWORD: $(TWINE_PASSWORD) TWINE_REPOSITORY_URL: $(TWINE_REPOSITORY_URL) displayName: 'Uploading to PyPI' condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/')

从这段配置可以推断其上传策略:

  • 多个并行任务产出的各版本 Windows wheel(wheel-3.10.x64…wheel-3.14.x86等 artifact)先被下载到工作区,再用CopyFiles把**/*.whl扁平化到 staging 目录;
  • 上传条件为startsWith(variables['Build.SourceBranch'], 'refs/tags/')——只有从 git 标签触发的构建才会真正上传到 PyPI,与 Jenkinsfile-pypi 的pypi_前缀分支策略属于同一思路:把"发布"与"日常构建"严格区分开。

3. 当前 Linux 轮子构建已迁移到 cibuildwheel

pyproject.toml 中配置了[tool.cibuildwheel],说明当前仓库的 wheel 构建主力已从手工 manylinux 容器命令迁移到 cibuildwheel:

[tool.cibuildwheel] build-verbosity = "3" test-command = [ "python {package}/testdata/pymod/import_db.py", "python {package}/testdata/pymod/import_rdb.py", "python {package}/testdata/pymod/import_tl.py", "python {package}/testdata/pymod/import_lib.py", "python {package}/testdata/pymod/import_lay.py", "TESTSRC={package} python {package}/testdata/pymod/pya_tests.py" ] skip = "pp* cp36-* cp37-* cp38-* cp39-*" [tool.cibuildwheel.linux] before-all = "source {project}/ci-scripts/docker/docker_prepare.sh" archs = ["auto64"] environment = { PATH="/usr/lib/ccache:/usr/lib64/ccache:/usr/lib/ccache/bin:$PATH" } before-build = "ccache -s" environment-pass = ["HOST_CCACHE_DIR"] [tool.cibuildwheel.macos] repair-wheel-command = "delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v --ignore-missing-dependencies {wheel}"

可见:

  • 构建前用 ci-scripts/docker/docker_prepare.sh 准备 manylinux/musllinux 环境(安装 zlib、curl、expat、libpng 开发包并配置 ccache),ccache上限设为 5G;
  • 每个 wheel 构建后仍运行testdata/pymod/下的同一组导入测试与pya_tests.py,与容器脚本一脉相承;
  • macOS 侧用delocate-wheel(约束见 cibw_constraints.txt 中delocate<=0.10.7)修复依赖,对应 Linux 侧的auditwheel repair职责;
  • skip = "pp* cp36-* cp37-* cp38-* cp39-*"表示不构建 PyPy 与 Python 3.6–3.9 的 wheel,这是当前发布矩阵的实际兼容边界。

四、把完整流程串起来:一次 KLayout PyPI 发布

结合文档与当前源码,一次发布实际经历以下环节(以仓库现状为准):

  1. 定版:确认 version.sh 中KLAYOUT_PYPI_VERSION为目标版本(当前为0.30.12)。sdist/wheel 的包名版本都由它决定。
  2. 构建 wheel:Linux 走 cibuildwheel(manylinux 容器 +docker_prepare.sh)或 Jenkins 的jenkins-manylinux2014_x86_64-pypi镜像 + docker_build_jenkins.sh;Windows 走 Azure Pipelines 各 Python 版本任务;macOS 由 cibuildwheel +delocate-wheel处理。
  3. 构建源码包:setup.py sdist(容器内为--formats=zip -d /io/wheelhouse)。内容清单由 MANIFEST.in 决定,包含全部 C++ 模块源码与pysetup.toml模块描述文件。
  4. 构建后自检:安装产物并运行testdata/pymod/的import_db.py、import_rdb.py、import_tl.py、import_lib.py、import_lay.py、pya_tests.py。
  5. 上传:twine upload --skip-existing wheelhouse/...whl ...zip,凭据来自 CI 变量(TWINE_USERNAME/TWINE_PASSWORD/TWINE_REPOSITORY_URL),且仅在发布专用分支(pypi_*)或 git 标签(refs/tags/*)触发的构建中执行。

五、实操要点与注意事项

  • 不要重复发布同一版本号:PyPI 禁止覆盖已上传文件,--skip-existing只是让重跑不报错,若修改了构建产物仍需提升KLAYOUT_PYPI_VERSION后重新打 tag/走发布分支。
  • sdist 与 wheel 要成对发布:文档的"wheel 先行、sdist 随后"顺序保证了即使某平台缺 wheel,pip 也能回退到 sdist 本地编译(前提是有 C++ 工具链与 curl/expat/png 等构建依赖,见 setup.py 头部注释列出的 build requirements)。
  • travis upload命令已退役:若按旧文档操作,请将其理解为twine upload的前身;当前仓库所有发布路径均以twine upload --skip-existing为准。
  • 凭据管理:早期交互式输入 username/password 的方式只适合一次性手工发布;自动化场景一律使用TWINE_*环境变量注入,且上传动作被分支/标签条件守卫。

参考文件清单

  • 本文核心文档:ci-scripts/twine/README.md
  • 版本中央配置:version.sh
  • 打包脚本:setup.py、MANIFEST.in、pyproject.toml、cibw_constraints.txt
  • 构建脚本:ci-scripts/docker/README.md、ci-scripts/docker/docker_build.sh、ci-scripts/docker/docker_build_jenkins.sh、ci-scripts/docker/docker_prepare.sh
  • 发布流水线:Jenkinsfile-pypi、azure-pipelines.yml
  • 构建后测试脚本:testdata/pymod/
  • 硬件开发
  • 桌面应用
  • 图形学

【免费下载链接】klayout

KLayout Main Sources

项目地址:https://gitcode.com/gh_mirrors/kl/klayout
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 17:44:26

C51单片机流水灯仿真入门:Proteus+Keil搭建与避坑指南

简介&#xff1a;一套基于C51单片机的流水灯Proteus仿真学习资料&#xff0c;面向51单片机初学者和电子实训课程学员&#xff0c;可解决多花样流水灯编程、仿真验证与代码烧录等入门问题。工程内包含C语言源码、Keil工程文件、Proteus仿真工程文件、Hex可烧录文件以及运行演示视…

作者头像 李华
网站建设 2026/10/14 17:44:23

Codex 多智能体接力怎么不丢信息?用交接单固定输入与限制

Codex 多智能体接力怎么不丢信息?用交接单固定输入与限制 本文围绕“多智能体交接单”设计一个可离线复核的教学场景:不调用在线模型、不连接设备、不上传业务数据。核验日期为 2026-10-14。 一、先定义本题真正要避免的错误 把子任务只写成“继续处理”时,下一位既不知道可…

作者头像 李华
网站建设 2026/10/14 17:43:19

工具部署在远程服务器,怎么调本机 localhost 的接口?一个油猴插件方案

正文 分享一个很常见但很折磨人的场景。 我们把 API 调试工具部署在了公司内网服务器上&#xff0c;大家浏览器打开就能用&#xff0c;很方便。但问题来了&#xff1a;我正在开发的接口跑在自己电脑的 localhost:8080 上&#xff0c;服务器上的网页怎么可能访问得到我本机的服务…

作者头像 李华
网站建设 2026/10/14 17:42:44

基于Retinex多尺度色调映射的HDR图像增强毕设实现与调参指南

1. 项目缘起与核心问题拆解1.1 为什么HDR色调映射值得死磕做图像处理方向的毕设&#xff0c;绕不开的一个经典命题就是高动态范围图像的显示问题。简单说&#xff0c;现实世界的光照跨度极大&#xff0c;从烛光到正午阳光&#xff0c;亮度差异可以跨越好几个数量级&#xff0c;…

作者头像 李华
网站建设 2026/10/14 17:42:30

openHiTLS 开源密码套件全解:五大组件架构、特性全景与 CMake 构建实战

密码学网络安全 【免费下载链接】openHiTLS 旨在打造算法先进、性能卓越、高效敏捷、安全可靠的密码套件&#xff0c;通过轻量级、可剪裁的软件技术架构满足各行业不同场景的多样化要求&#xff0c;让密码技术应用更简单&#xff0c;同时探索后量子等先进算法创新实践&#xff…

作者头像 李华
网站建设 2026/10/14 17:42:30

STM32F103 ADC+LCD+串口三外设协同设计实战

简介&#xff1a;本资源是一套基于STM32F103ZET6的嵌入式综合实践工程&#xff0c;面向嵌入式初学者与课程设计者&#xff0c;聚焦ADC电压采集、LCD实时显示与UART串口数据上传三大核心功能&#xff0c;解决模拟信号获取—本地可视化—远程传输的一体化开发需求。压缩包共88个文…

作者头像 李华