- 硬件开发
- 桌面应用
- 图形学
【免费下载链接】klayout
KLayout Main Sources
本文以仓库中的 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 *.whl | twine 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 发布
结合文档与当前源码,一次发布实际经历以下环节(以仓库现状为准):
- 定版:确认 version.sh 中
KLAYOUT_PYPI_VERSION为目标版本(当前为0.30.12)。sdist/wheel 的包名版本都由它决定。 - 构建 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处理。 - 构建源码包:
setup.py sdist(容器内为--formats=zip -d /io/wheelhouse)。内容清单由 MANIFEST.in 决定,包含全部 C++ 模块源码与pysetup.toml模块描述文件。 - 构建后自检:安装产物并运行
testdata/pymod/的import_db.py、import_rdb.py、import_tl.py、import_lib.py、import_lay.py、pya_tests.py。 - 上传:
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
相关推荐
runanywhere Python 发行包构建与 PyPI 发布全流程:从 pybind11 Wheel 到 twine 上传
runanywhere Python 发行包构建与 PyPI 发布全流程:从 pybind11 Wheel 到 twine 上传 runanywhere 是 R
AI模型推理服务推理引擎本地部署多模态终极指南:如何用 Twine 快速发布 Python 包到 PyPI
终极指南:如何用 Twine 快速发布 Python 包到 PyPI Twine 是 Python 包发布的终极利器!🚀 这个强大的工具专门用于将 Pytho
开发工具OpenUSD 的 PyPI 打包与发布指南:从 build_scripts/pypi 到 usd-core Wheel 包
OpenUSD 的 PyPI 打包与发布指南:从 build_scripts/pypi 到 usd core Wheel 包 本篇技术指南聚焦 OpenUSD
图形学3D渲染
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考