Bazel中cc_binary/cc_library的copts -I参数如何使用Bazel标签
我明白你想在Bazel的cc_library(或者cc_binary)的copts参数里用Bazel标签来指定头文件搜索路径,而不是写死硬编码的路径对吧?直接在-I后面写Bazel标签(比如-I//libs/foo/include)是行不通的,因为Bazel不会自动解析copts里的标签语法,但有两种更合适的方案可以实现你的需求,而且更符合Bazel的最佳实践:
1. 优先使用includes属性(最推荐)
Bazel为C++规则(cc_library/cc_binary等)提供了专门的includes属性,用来指定头文件搜索目录,它直接支持Bazel标签或者相对路径,Bazel会自动帮你处理路径解析,不需要手动写-I,还能正确维护依赖关系,完全替代你想要的-I<target-label>效果。
示例代码如下:
cc_library( name = "foo", srcs = ["src/func.cxx"], hdrs = ["include/foo/func.h"], # 直接用Bazel标签指定要添加的头文件搜索目录 includes = ["//libs/foo/include"], visibility = ["//visibility:public"], )
这样配置后,Bazel会自动把//libs/foo/include目录加入到编译的头文件搜索路径中,和手动写-Ilibs/foo/include效果完全一致,但不需要硬编码路径。
2. 若必须用copts,搭配$(location)占位符
如果因为某些特殊场景必须通过copts来添加-I参数,可以借助Bazel的$(location)占位符来实现标签解析,步骤如下:
第一步:在目标目录的BUILD文件中定义可访问的target
比如在//libs/foo的BUILD文件里,先把include目录标记为可被引用的目标:
# 直接导出include目录,让其他包可以引用 exports_files(["include"], visibility = ["//visibility:public"])
第二步:在你的cc_library中引用这个target
在copts里用$(location)占位符获取该目录的实际路径:
cc_library( name = "foo", srcs = ["src/func.cxx"], hdrs = ["include/foo/func.h"], # 用$(location)将Bazel标签替换为实际文件系统路径 copts = ["-I$(location //libs/foo/include)"], visibility = ["//visibility:public"], )
如果你的场景需要用filegroup管理目录下的文件,也可以先定义filegroup再引用:
# 在//libs/foo/BUILD中 filegroup( name = "foo_include_files", srcs = glob(["include/**/*.h"]), visibility = ["//visibility:public"], )
然后在cc_library中:
cc_library( name = "foo", srcs = ["src/func.cxx"], hdrs = ["include/foo/func.h"], copts = ["-I$(location //libs/foo:foo_include_files)/.."], # 必须添加依赖,否则Bazel无法解析占位符 deps = ["//libs/foo:foo_include_files"], visibility = ["//visibility:public"], )
这里的/..是因为$(location)返回的是filegroup中某个文件的路径,拼接后就能回到include目录本身。
不过还是要强调,第一种用includes的方案是最省心的,不需要处理路径拼接的问题,也更符合Bazel的依赖管理逻辑。
备注:内容来源于stack exchange,提问作者jellobird

