You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Wheel包中随自研共享库一同打包第三方共享库?

当然可行!这在Python扩展打包场景里太常见了——尤其是当你的C++扩展依赖外部共享库时,总不能让用户自己去装那些库对吧?下面给你几种实用的实现方案:

方法一:手动指定要包含的共享库

如果你的第三方.so库位置固定,最简单的方式是通过setuptools的package_data配合MANIFEST.in来配置:

步骤1:整理项目结构

假设你的项目结构如下:

my_package/
├── __init__.py
├── my_extension.so  # 你编译好的扩展
└── libs/
    └── thirdparty.so  # 要打包的第三方库

步骤2:修改setup.py

在setup()函数里添加package_data配置,告诉setuptools要包含哪些文件:

from setuptools import setup, find_packages

setup(
    name="my_package",
    version="0.1.0",
    packages=find_packages(),
    # 指定要包含的共享库
    package_data={
        "my_package": ["libs/*.so"],
    },
)

步骤3:创建MANIFEST.in

在项目根目录创建这个文件,确保打包时能捕获到这些.so文件:

include my_package/libs/*.so

方法二:自动收集扩展依赖的共享库

如果你的C++扩展是动态链接第三方.so的,可以通过自定义build_ext命令,自动找出依赖的库并复制到包目录里,不用手动整理:

修改setup.py如下:

import os
import shutil
import subprocess
from setuptools import setup, Extension
from setuptools.command.build_ext import build_ext

class CustomBuildExt(build_ext):
    def run(self):
        # 先执行默认的扩展编译流程
        super().run()
        
        # 获取编译好的扩展文件路径
        ext_full_path = self.get_ext_fullpath(self.extensions[0].name)
        # 用ldd命令找出扩展依赖的共享库(Linux下)
        ldd_output = subprocess.run(
            ["ldd", ext_full_path],
            capture_output=True,
            text=True
        ).stdout
        
        # 遍历依赖,过滤掉系统库,复制第三方库到包内
        for line in ldd_output.splitlines():
            if "=>" in line and not line.startswith("\tlinux-vdso.so"):
                parts = line.split("=>")
                lib_path = parts[1].strip().split(" ")[0]
                # 判断是否为第三方库(排除系统默认路径的库)
                if not lib_path.startswith(("/usr/lib", "/lib", "/usr/local/lib")):
                    dest_dir = os.path.join(os.path.dirname(ext_full_path), "libs")
                    os.makedirs(dest_dir, exist_ok=True)
                    shutil.copy2(lib_path, dest_dir)

setup(
    name="my_package",
    version="0.1.0",
    ext_modules=[Extension("my_package.my_extension", sources=["src/my_extension.cpp"])],
    cmdclass={"build_ext": CustomBuildExt},
    package_data={
        "my_package": ["libs/*.so"],
    },
)

方法三:用专用工具处理(跨平台推荐)

不同平台有专门的工具帮你自动处理共享库打包,省心又规范:

  • Linux:用auditwheel,它会自动把依赖的.so嵌入wheel,还能生成兼容多Linux发行版的manywheel包
    1. 安装工具:pip install auditwheel
    2. 先构建基础wheel:python3 setup.py bdist_wheel
    3. 修复wheel并包含依赖:auditwheel repair dist/your_package-*.whl
  • macOS:用delocate-wheel,功能类似auditwheel,处理macOS的.dylib依赖
  • Windows:可以用wheeltools或者手动复制.dll(对应Linux的.so)到包目录,再配置package_data

注意:打包完成后,要确保Python能找到这些共享库。可以在包的__init__.py里做路径配置:

import os
import ctypes

lib_dir = os.path.join(os.path.dirname(__file__), "libs")
# 方式1:直接加载指定路径的库
ctypes.CDLL(os.path.join(lib_dir, "thirdparty.so"))
# 方式2:设置环境变量,让系统能找到库
os.environ["LD_LIBRARY_PATH"] = f"{lib_dir}:{os.environ.get('LD_LIBRARY_PATH', '')}"

# 然后导入你的扩展
from .my_extension import *

内容的提问来源于stack exchange,提问作者Frank C.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:37:23