如何通过py_binary与genrule生成C++文件并解决构建报错
解决Bazel生成C++文件并引入到cc_binary的问题
问题根源
Bazel采用沙盒构建机制,不允许genrule直接写入原代码目录(比如你的weights文件夹),所有生成文件必须放在Bazel管理的输出目录下。之前的报错正是因为尝试直接写入原目录,导致Bazel无法追踪到生成的文件。
修复步骤
1. 调整Python脚本参数
修改scripts/blob_to_cpp.py,让它支持接收输入文件路径、输出头文件路径、输出源文件路径三个参数,确保能将生成内容写入Bazel指定的输出位置:
import sys def main(): if len(sys.argv) != 4: print("Usage: blob_to_cpp.py <input_blob> <output_header> <output_source>") sys.exit(1) input_path = sys.argv[1] header_path = sys.argv[2] source_path = sys.argv[3] # 保留你原有的文件生成逻辑,将内容写入header_path和source_path # 示例(替换成你的实际逻辑): with open(header_path, "w") as h: h.write(f"#pragma once\n// Generated from {input_path}") with open(source_path, "w") as s: s.write(f"#include \"{header_path.split('/')[-1]}\"\n// Generated content") if __name__ == "__main__": main()
2. 编写正确的生成宏和BUILD规则
在根目录BUILD文件中,替换原有的宏和规则,确保生成文件被Bazel正确追踪,并能被cc_binary通过#include "weights/rt_alb.h"引入:
# 1. 声明Python工具 py_binary( name = "blob_to_cpp", srcs = ["scripts/blob_to_cpp.py"], ) # 2. 定义生成C++文件并封装为cc_library的宏 def generate_cpp_from_blob_cc_library(name, blob_file): # 从blob文件名提取基础名称(比如weights/rt_alb.tza -> rt_alb) base_name = blob_file.split("/")[-1].split(".")[0] gen_header = f"weights/{base_name}.h" gen_source = f"weights/{base_name}.cpp" genrule( name = f"{name}_gen", srcs = [blob_file], outs = [gen_header, gen_source], # 调用Python脚本,传入输入文件和两个输出文件的路径 cmd = "$(location //:blob_to_cpp) $(SRCS) $(location {gen_header}) $(location {gen_source})", tools = ["//:blob_to_cpp"], ) # 将生成的文件封装为cc_library,供cc_binary依赖 cc_library( name = name, srcs = [gen_source], hdrs = [gen_header], # 将当前目录加入include路径,让cc_binary能通过"weights/rt_alb.h"找到头文件 includes = ["."], visibility = ["//visibility:public"], ) # 3. 调用宏生成权重对应的C++库 generate_cpp_from_blob_cc_library( name = "rt_alb_weights", blob_file = "weights/rt_alb.tza", ) # 4. 定义你的cc_binary,依赖生成的库 cc_binary( name = "Demo", srcs = ["main.cpp"], deps = [":rt_alb_weights"], )
3. 验证include路径
在你的main.cpp中,直接使用#include "weights/rt_alb.h"即可,Bazel会通过cc_library的includes = ["."]配置,将生成的weights虚拟目录加入编译的include路径。
关键说明
- 所有生成文件必须在
genrule的outs中声明,Bazel会自动管理这些文件的生成路径(位于bazel-out目录下)。 - 通过
cc_library封装生成的文件,既能保证构建顺序(先生成文件再编译),又能通过includes属性让cc_binary找到头文件。
内容的提问来源于stack exchange,提问作者Vertexwahn
相关产品推荐
相关产品推荐

