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

如何将调用其他脚本的Bazel生成脚本打包为Pip Wheel

问题描述

尝试为Bazel生成的py_binary脚本创建wheel包时遇到路径问题,简化示例如下:

目录结构

.
├── MANIFEST.in
├── bin
│   ├── __init__.py
│   ├── mytest
│   └── mytest.lib
│       ├── used1
│       └── used2
└── setup.py

关键文件内容

  • bin/mytest(入口脚本,无法修改):
#!/bin/bash

bash $0.lib/used1
bash $0.lib/used2

该脚本依赖$0.lib寻找与自身同目录的mytest.lib子目录脚本。

  • 原setup.py:
import setuptools

setuptools.setup(
    name="mytest",
    version="0.0.1",
    maintainer="",
    maintainer_email="",
    packages=setuptools.find_packages(),
    install_requires=[],
    scripts=["bin/mytest"],
    include_package_data=True,
)
  • MANIFEST.in:
graft bin

安装后问题

执行python setup.py bdist_wheel和pip install dist/mytest-0.0.1-py3-none-any.whl后,运行mytest报错:MY_ENV/bin/mytest.lib/used1不存在,核心问题:

  1. mytest.lib被安装到MY_ENV/lib/python3.8/site-packages/bin,而非脚本所在的MY_ENV/bin;
  2. 原脚本mytest要求mytest.lib与自身同目录,但安装后两者路径分离。

限制:无法修改Bazel生成的mytest和mytest.lib文件,但可添加其他文件或修改打包配置。


解决方案

方案一:把mytest.lib直接装到脚本同目录

修改setup.py,用data_files指定将mytest.lib目录安装到环境的bin文件夹,和mytest脚本放在一起,原脚本的路径逻辑就能正常工作:

import setuptools
import os

# 遍历mytest.lib下的所有文件,整理成data_files需要的格式
lib_files = []
lib_root = "bin/mytest.lib"
for root, _, files in os.walk(lib_root):
    for file in files:
        src_path = os.path.join(root, file)
        # 目标路径为bin/mytest.lib/对应子路径
        dest_path = os.path.join("bin", os.path.relpath(root, "bin"))
        lib_files.append((dest_path, [src_path]))

setuptools.setup(
    name="mytest",
    version="0.0.1",
    maintainer="",
    maintainer_email="",
    packages=setuptools.find_packages(),
    install_requires=[],
    scripts=["bin/mytest"],
    data_files=lib_files,
    # 关闭include_package_data避免重复打包
    # include_package_data=True,
)

同时修改MANIFEST.in确保文件被正确包含:

include bin/mytest
graft bin/mytest.lib

安装后,mytest和mytest.lib都会出现在MY_ENV/bin目录,原脚本的$0.lib就能找到依赖文件。

方案二:加个包装脚本做入口

创建一个新的bash脚本bin/mytest_wrapper,代替原mytest作为wheel的入口,让它自动找到mytest.lib的实际安装路径:

#!/bin/bash
# 自动获取site-packages下的bin目录路径
SITE_PACKAGES_BIN=$(python -c "import site; print(site.getsitepackages()[0])")/bin
# 直接执行mytest.lib下的脚本,绕开原脚本的路径限制
bash "$SITE_PACKAGES_BIN/mytest.lib/used1"
bash "$SITE_PACKAGES_BIN/mytest.lib/used2"

然后修改setup.py,把包装脚本作为入口,并且安装后命名为mytest:

import setuptools

setuptools.setup(
    name="mytest",
    version="0.0.1",
    maintainer="",
    maintainer_email="",
    packages=setuptools.find_packages(),
    install_requires=[],
    # 将包装脚本安装为mytest命令
    scripts=[("mytest", "bin/mytest_wrapper")],
    include_package_data=True,
)

方案三:用Python入口脚本动态找路径

利用bin目录下的__init__.py将其作为Python子包,创建bin/mytest_entry.py脚本:

import os
import subprocess
import site

# 获取site-packages下的bin目录路径
site_bin = os.path.join(site.getsitepackages()[0], "bin")
# 执行mytest.lib下的脚本
used1_path = os.path.join(site_bin, "mytest.lib", "used1")
used2_path = os.path.join(site_bin, "mytest.lib", "used2")

subprocess.run(["bash", used1_path], check=True)
subprocess.run(["bash", used2_path], check=True)

修改setup.py,用console_scripts生成mytest命令:

import setuptools

setuptools.setup(
    name="mytest",
    version="0.0.1",
    maintainer="",
    maintainer_email="",
    packages=setuptools.find_packages(),
    install_requires=[],
    entry_points={
        'console_scripts': [
            'mytest = bin.mytest_entry:main',
        ],
    },
    include_package_data=True,
)

同时确保MANIFEST.in包含所有文件:

graft bin

安装后,mytest命令会调用这个Python脚本,自动找到mytest.lib的位置并执行脚本。


内容的提问来源于stack exchange,提问作者XuanInsr

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 22:43:27