两种依赖OpenCV4的Bazel cc_library定义方式差异对比
Bazel中两种OpenCV4 cc_library定义方式的差异对比
在Bazel的WORKSPACE中通过new_local_repository引入OpenCV4后,存在两种cc_library定义方式:一种是通过linkopts指定链接选项(opencv4_a),另一种是将.so文件作为srcs并设置linkstatic=1(opencv4_b)。以下是两者的核心差异,以及依赖它们的cc_binary在使用上的区别:
一、两种cc_library定义方式的差异
1. 依赖追踪与链接逻辑
- opencv4_a:通过
linkopts直接给编译器传递链接参数,Bazel不会解析这些.so文件的内部依赖关系,仅在链接阶段原封不动转发选项。如果库之间存在依赖(比如core依赖其他基础库),需要手动在linkopts中按正确顺序添加,否则会出现链接错误。 - opencv4_b:将.so文件作为
srcs传入并设置linkstatic=1,Bazel会把这些共享库当作静态库处理,自动解析库之间的依赖关系并维护链接顺序,无需手动调整。
2. 路径灵活性
- opencv4_a:
linkopts中硬编码了-L/usr/local/lib绝对路径,一旦OpenCV安装路径变更,必须手动修改该配置,可移植性差。 - opencv4_b:通过
glob从new_local_repository映射的仓库路径下读取.so文件,路径基于仓库相对位置,只要new_local_repository的path配置正确,无需硬编码绝对路径,适配性更强。
3. 构建缓存与增量构建
- opencv4_a:Bazel无法感知
linkopts中.so文件的变化,当这些库更新时,不会自动触发依赖目标的增量构建,需要手动清理缓存或重新全量构建。 - opencv4_b:Bazel会追踪
srcs中.so文件的修改时间,库文件更新时会自动触发依赖它的cc_binary增量构建,缓存逻辑更可靠。
4. 依赖传递与可见性
- opencv4_a:默认仅当前包可访问(未设置
visibility),且链接选项无法向上传递,若其他库依赖opencv4_a,上层目标需重复配置链接参数。 - opencv4_b:显式设置
visibility = ["//visibility:public"],所有包均可依赖;同时Bazel会自动传递库的依赖关系给上层目标,无需重复配置。
二、依赖它们的cc_binary的使用区别
1. 运行环境依赖
- 依赖opencv4_a的cc_binary:运行时要求目标机器的
/usr/local/lib下存在指定的OpenCV.so文件,因为链接仅记录动态库的路径和名称,运行时动态加载。若目标机器的OpenCV路径或版本不匹配,会出现找不到库的错误。 - 依赖opencv4_b的cc_binary:
linkstatic=1会让Bazel尝试将.so文件的代码静态链接到二进制中(仅适用于位置无关代码的共享库),最终产物对系统OpenCV动态库的依赖大幅降低,甚至无需依赖。但如果这些.so本身依赖其他系统库(如libpng、libjpeg),运行时仍需这些依赖存在。
2. 链接错误排查难度
- 依赖opencv4_a的cc_binary:出现链接错误时,需手动检查
linkopts中的库是否齐全、顺序是否正确,Bazel无法提供依赖关系辅助,排查成本高。 - 依赖opencv4_b的cc_binary:Bazel管理依赖顺序,若出现错误,通常是缺少.so文件或库本身存在问题,可通过
bazel query等工具分析依赖链,更容易定位问题。
3. 跨平台适配性
- 依赖opencv4_a的cc_binary:
linkopts硬编码了Linux平台的.so后缀和绝对路径,无法直接适配Windows(.dll)、macOS(.dylib)等平台,需编写多平台专属配置。 - 依赖opencv4_b的cc_binary:可通过
select配合不同平台的glob规则,自动选择对应平台的库文件,更易实现跨平台构建。
三、相关代码示例
WORKSPACE配置
new_local_repository( name = "linux_opencv", build_file = "@//third_party:opencv_linux.BUILD", path = "/usr/local", )
opencv4_a的cc_library定义
cc_library( name = "opencv4_a", hdrs = glob([ "include/opencv4/opencv2/**/*.h*", ]), includes = ["include/opencv4/"], linkopts = [ "-L/usr/local/lib", "-l:libopencv_core.so", "-l:libopencv_calib3d.so", "-l:libopencv_features2d.so", "-l:libopencv_highgui.so", "-l:libopencv_imgcodecs.so", "-l:libopencv_imgproc.so", "-l:libopencv_video.so", "-l:libopencv_videoio.so", ], )
opencv4_b的cc_library定义
cc_library( name = "opencv4_b", srcs = glob([ "lib/libopencv_core.so", "lib/libopencv_highgui.so", "lib/libopencv_imgcodecs.so", "lib/libopencv_imgproc.so", "lib/libopencv_video.so", "lib/libopencv_videoio.so", ]), hdrs = glob(["include/opencv4/opencv2/**/*.h*"]), includes = ["include/opencv4/"], linkstatic = 1, visibility = ["//visibility:public"], )
依赖两种库的cc_binary配置
cc_binary( name = "executable", srcs = ["a.cpp", "c.cpp", "c.h"], deps = [":opencv4_a"], # 替换为deps = [":opencv4_b"]即可依赖第二种定义 )
内容的提问来源于stack exchange,提问作者wssbygone
相关产品推荐
相关产品推荐

