在Bazel中基于WORKSPACE实现带补丁的Python构建工具方案
解决方案:基于WORKSPACE的Python工具依赖C++库构建流程
以下是针对你提出的四个问题的具体解决方法,结合WORKSPACE、BUILD配置和补丁应用的完整示例:
问题1:Python脚本相对导入报错
相对导入失败是因为Bazel运行Python脚本时,默认不会将包目录加入sys.path。解决方法是将foo包定义为py_library,再用py_binary封装baz.py,确保导入路径正确:
在foo包对应的BUILD文件(如foo/BUILD)中添加:
py_library( name = "foo_lib", srcs = glob(["**/*.py"]), visibility = ["//visibility:public"], ) py_binary( name = "baz_script", main = "bar/baz.py", deps = [":foo_lib"], visibility = ["//visibility:public"], )
这样Bazel会自动处理Python包的导入路径,from . import qux就能正常找到父包。
问题2:给Python包应用补丁
使用http_archive拉取foo包后,通过patches和patch_args参数直接应用补丁,再用py_repository将其转为Python依赖。注意补丁路径要相对于WORKSPACE目录:
在WORKSPACE中添加:
http_archive( name = "foo_raw", urls = ["https://github.com/xxx/foo/archive/refs/tags/v1.0.0.tar.gz"], strip_prefix = "foo-1.0.0", patches = ["//:baz.patch"], # 相对于WORKSPACE的补丁路径 patch_args = ["-p1"], # 根据补丁生成时的层级调整参数 ) py_repository( name = "foo", root = "@foo_raw//", )
如果补丁是本地文件,需在根目录BUILD文件中声明为filegroup:
filegroup( name = "baz_patch", srcs = ["baz.patch"], visibility = ["//visibility:public"], )
问题3:自动生成requirements_lock.txt
使用rules_python的pip_generate_lockfile函数,在WORKSPACE中自动生成锁文件,无需手动执行bazel run //:requirements.update:
load("@rules_python//python:pip.bzl", "pip_generate_lockfile", "pip_parse") pip_generate_lockfile( name = "generate_requirements_lock", requirements = "//:requirements.txt", # 你的依赖清单 output = "//:requirements_lock.txt", ) pip_parse( name = "pip_deps", requirements_lock = "@//:requirements_lock.txt", ) load("@pip_deps//:requirements.bzl", "pip_install") pip_install()
构建时Bazel会自动生成锁文件,无需手动预处理。
问题4:foo包无入口点导致run_binary报错
直接运行未定义入口点的包会失败,需调用自定义的baz_script(问题1中定义的py_binary)。在根目录BUILD文件中用genrule运行脚本生成C++源文件:
genrule( name = "generate_cpp_sources", outs = ["generated_source.cpp", "generated_header.h"], cmd = "$(execpath @foo//:baz_script) --output $(@D)", tools = ["@foo//:baz_script"], ) cc_library( name = "my_cpp_lib", srcs = ["src/my_lib.cpp", ":generate_cpp_sources"], hdrs = ["include/my_lib.h", ":generate_cpp_sources"], visibility = ["//visibility:public"], )
也可直接用run_binary调用自定义目标:
load("@rules_python//python:run_binary.bzl", "run_binary") run_binary( name = "run_baz_script", tool = "@foo//:baz_script", arguments = [ "--output", "$(location generated_source.cpp)", ], outputs = ["generated_source.cpp"], )
完整配置示例
WORKSPACE文件
workspace(name = "my_cpp_project") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") # 导入rules_python http_archive( name = "rules_python", urls = ["https://github.com/bazelbuild/rules_python/releases/download/0.25.0/rules_python-0.25.0.tar.gz"], sha256 = "f999a87c42222784f75b37a89144c1b9395e977e9d50974cb754a6b19d75e954", ) # 自动生成锁文件并导入Python依赖 load("@rules_python//python:pip.bzl", "pip_generate_lockfile", "pip_parse") pip_generate_lockfile( name = "generate_requirements_lock", requirements = "//:requirements.txt", output = "//:requirements_lock.txt", ) pip_parse( name = "pip_deps", requirements_lock = "@//:requirements_lock.txt", ) load("@pip_deps//:requirements.bzl", "pip_install") pip_install() # 拉取并修补foo包 http_archive( name = "foo_raw", urls = ["https://github.com/xxx/foo/archive/v1.0.0.tar.gz"], strip_prefix = "foo-1.0.0", patches = ["//:baz.patch"], patch_args = ["-p1"], ) py_repository( name = "foo", root = "@foo_raw//", )
根目录BUILD文件
filegroup( name = "baz_patch", srcs = ["baz.patch"], visibility = ["//visibility:public"], ) genrule( name = "generate_cpp_sources", outs = ["generated_source.cpp", "generated_header.h"], cmd = "$(execpath @foo//:baz_script) --output $(@D)", tools = ["@foo//:baz_script"], ) cc_library( name = "my_cpp_lib", srcs = ["src/my_lib.cpp", ":generate_cpp_sources"], hdrs = ["include/my_lib.h", ":generate_cpp_sources"], visibility = ["//visibility:public"], )
foo/BUILD(手动添加)
如果拉取的foo包无BUILD文件,需手动创建@foo_raw//:BUILD:
py_library( name = "foo_lib", srcs = glob(["**/*.py"]), visibility = ["//visibility:public"], ) py_binary( name = "baz_script", main = "bar/baz.py", deps = [":foo_lib"], visibility = ["//visibility:public"], )
内容的提问来源于stack exchange,提问作者cstal
相关产品推荐
相关产品推荐

