如何通过setuptools自动获取适配架构的远程交叉编译库?
可行解决方案
方案1:在setup.py中添加架构感知的依赖下载逻辑
直接在setup.py执行核心编译逻辑前,编写代码检测当前系统架构,从依赖仓库拉取对应预编译二进制包并解压到指定目录,再让CMake指向该路径完成链接。
具体操作:
- 编写架构检测函数,映射到依赖仓库的命名规则:
import platform def get_target_arch(): sys_arch = platform.machine() # 根据你的依赖仓库架构命名规则调整映射关系 arch_mapping = { 'x86_64': 'x86_64-linux-gnu', 'aarch64': 'arm64-linux-gnu', 'arm64': 'arm64-apple-darwin', 'AMD64': 'x86_64-w64-mingw32' } return arch_mapping.get(sys_arch, sys_arch) - 实现依赖包下载与解压逻辑:
import os import tarfile from urllib.request import urlopen DEPENDENCY_BASE_URL = "https://your-dependency-repo.com/prebuilt/{arch}/uno-required-libs.tar.gz" LOCAL_DEP_DIR = os.path.join(os.path.dirname(__file__), "prebuilt_deps") def fetch_prebuilt_deps(): if os.path.exists(os.path.join(LOCAL_DEP_DIR, "lib")) and os.path.exists(os.path.join(LOCAL_DEP_DIR, "include")): return # 跳过已下载的依赖 target_arch = get_target_arch() download_url = DEPENDENCY_BASE_URL.format(arch=target_arch) with urlopen(download_url) as resp, tarfile.open(fileobj=resp, mode="r|gz") as tar: tar.extractall(path=LOCAL_DEP_DIR) # 在setup()调用前执行下载 fetch_prebuilt_deps() - 修改CMakeLists.txt,指定依赖查找路径:
set(PREBUILT_DEP_DIR "${CMAKE_SOURCE_DIR}/prebuilt_deps") find_library(REQUIRED_LIB NAMES uno-core PATHS "${PREBUILT_DEP_DIR}/lib" NO_DEFAULT_PATH) include_directories("${PREBUILT_DEP_DIR}/include") - 若使用scikit-build编译,在setup.py中传递依赖路径参数:
from skbuild import setup setup( name="uno-python-binding", cmake_args=[ f"-DPREBUILT_DEP_DIR={LOCAL_DEP_DIR}", # 其他CMake编译参数 ], # 其他setup配置项 )
方案2:自定义setuptools命令扩展下载流程
通过扩展setuptools的cmdclass,自定义一个依赖下载命令,并让安装命令依赖该流程,确保编译前依赖已就绪。
示例代码:
from setuptools import setup, Command class FetchDepsCommand(Command): description = "Download architecture-specific precompiled dependencies" user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): # 复用方案1中的fetch_prebuilt_deps()逻辑 fetch_prebuilt_deps() # 让install命令自动触发依赖下载 class InstallWithDeps(Command): description = "Install package after fetching dependencies" user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): FetchDepsCommand().run() # 调用标准install流程 self.run_command("install") setup( name="uno-python-binding", cmdclass={ 'fetch_deps': FetchDepsCommand, 'install': InstallWithDeps }, # 其他setup配置项 )
方案3:CI预构建平台专属Python轮子
将依赖处理逻辑转移到CI流程,预先为每个目标架构构建包含预编译依赖的Python轮子,用户安装时pip会自动匹配对应架构的包。
操作步骤:
- 在GitHub Actions中为每个目标架构(如ubuntu-x86_64、macos-arm64、windows-x86_64)配置构建任务:
- 拉取对应架构的预编译依赖包
- 使用scikit-build编译Python绑定,将依赖库嵌入构建产物
- 用
auditwheel(Linux)或delocate(macOS)处理轮子,确保依赖库被正确打包
- 将所有架构的轮子上传到PyPI或私有仓库
- 用户执行
pip install uno-python-binding时,pip会自动下载适配本地架构的轮子,无需手动处理依赖
关键注意事项
- 架构检测逻辑要和依赖仓库的命名严格对齐,避免下载错误包
- 预编译依赖包必须包含编译所需的头文件和链接所需的共享库
- Windows平台需特别处理.dll文件的路径和运行时加载问题,可借助
delocate类工具打包进轮子 - 私有依赖仓库需在下载逻辑中添加身份验证(如通过环境变量传递token)
内容的提问来源于stack exchange,提问作者Charlie Vanaret - the Uno guy
相关产品推荐
相关产品推荐

