Bazel中SWIG规则的可选输出文件处理方案咨询
解决Bazel规则中SWIG条件生成.h文件的问题
问题核心
- SWIG是否生成
.h头文件,完全取决于.i接口文件是否启用了directors特性 - 固定声明输出
.h会导致未生成时报错;移除h_out配置后,生成的.h又无法被native.cc_binary的依赖系统识别,编译时找不到文件 - 尝试生成虚拟
.h会触发动作冲突,不可行
单规则下的最优解决思路
1. 动态检测directors特性,按需声明输出文件
在规则实现里读取.i文件内容,判断是否包含directors相关指令,动态决定是否将.h加入输出列表:
def _has_directors(ctx): content = ctx.file.source.read() # 检查SWIG directors相关的指令格式 return "%feature(directors)" in content or "%director" in content def _py_swig_gen_impl(ctx): # 声明固定输出的.cc文件 swig_cc_out = ctx.actions.declare_file(f"{ctx.label.name}_wrap.cc") outputs = [swig_cc_out] swig_h_out = None if _has_directors(ctx): # 按需声明.h输出文件 swig_h_out = ctx.actions.declare_file(f"{ctx.label.name}_wrap.h") outputs.append(swig_h_out) # 构建SWIG命令参数 args = ctx.actions.args() args.add("-python", "-c++") args.add("-o", swig_cc_out.path) if swig_h_out: args.add("-oh", swig_h_out.path) # 显式开启directors特性(如果.i里没写全局feature) args.add("-features", "directors") # 添加必要的头文件包含路径 for inc in ctx.attr.hdrs: args.add("-I", inc.dirname) ctx.actions.run( inputs = [ctx.file.source] + ctx.files.hdrs, outputs = outputs, executable = ctx.executable.swig, arguments = [args, ctx.file.source.path], ) # 生成CcInfo,把.h文件传递给下游C++目标 compilation_context = cc_common.create_compilation_context( headers = depset([swig_h_out]) if swig_h_out else depset() ) return [ DefaultInfo(files = depset(outputs)), CcInfo(compilation_context = compilation_context), ]
2. 用CcInfo传递头文件依赖
通过CcInfo将生成的.h文件注入到Bazel的依赖系统中,下游的cc_binary或cc_library依赖该规则时,会自动获取头文件路径,无需手动用glob捕获。
3. 规则定义调整
去掉固定的h_out输出声明,改为动态生成:
py_swig_gen = rule( implementation = _py_swig_gen_impl, attrs = { "source": attr.label(allow_single_file = [".i"]), "hdrs": attr.label_list(allow_files = [".h"], mandatory = False), "swig": attr.label( executable = True, cfg = "exec", default = Label("@swig//:swig"), ), }, # 只声明固定的.cc输出,.h按需生成 outputs = { "swig_cc_out": "%{name}_wrap.cc", }, )
效果验证
- 当
.i文件启用directors时,规则会生成.cc和.h,下游C++目标能正常找到头文件 - 未启用directors时,仅生成
.cc,不会出现输出文件缺失的报错
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

