如何使用Bazel构建使用OpenCV的项目

17

如何使用Bazel构建使用OpenCV库的C++代码?即,BUILD规则应该如何编写?

为了使用bazel编译以下代码,WORKSPACEBUILD文件应该是什么样子的:


#include "opencv2/opencv.hpp"
#include "iostream"

int main(int, char**) {
  using namespace cv;
  VideoCapture cap(0);
  Mat save_img; cap >> save_img;
  if(save_img.empty())
  {
    std::cerr << "ERROR >> Something is wrong with camera..." << std::endl;
  }
  imwrite("test.jpg", save_img);
  return 0;
}


我不明白为什么这个问题被关闭了,因为它并没有寻找离线资源。 - StayOnTarget
5个回答

33

有几种选择。最简单的方式可能是按照OpenCV网站建议的本地安装方法进行安装:

git clone https://github.com/Itseez/opencv.git
cd opencv/
mkdir build install
cd build
cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/path/to/opencv/install ..
make install

然后将以下内容添加到您的 WORKSPACE 文件中:

new_local_repository(
    name = "opencv",
    path = "/path/to/opencv/install",
    build_file = "opencv.BUILD",
)
在与WORKSPACE相同的目录下创建opencv.BUILD文件,并包含以下内容:
cc_library(
    name = "opencv",
    srcs = glob(["lib/*.so*"]),
    hdrs = glob(["include/**/*.hpp"]),
    includes = ["include"],
    visibility = ["//visibility:public"], 
    linkstatic = 1,
)

然后你的代码可以依赖于@opencv//:opencv,以链接到lib/下的.so文件并引用include/下的头文件。

然而,这不是非常便携。如果你想要一个便携式的解决方案(而且你有野心),你可以将OpenCV git存储库添加到你的工作区,并下载&构建它。类似这样:

# WORKSPACE
new_git_repository(
    name = "opencv",
    remote = "https://github.com/Itseez/opencv.git",
    build_file = "opencv.BUILD",
    tag = "3.1.0",
)

并将opencv.BUILD设置为类似以下内容:

cc_library(
    name = "core",
    visibility = ["//visibility:public"],
    srcs = glob(["modules/core/src/**/*.cpp"]),
    hdrs = glob([
        "modules/core/src/**/*.hpp", 
        "modules/core/include/**/*.hpp"]
    ) + [":module-includes"],
)

genrule(
    name = "module-includes",
    cmd = "echo '#define HAVE_OPENCV_CORE' > $@",
    outs = ["opencv2/opencv_modules.hpp"],
)

...

那么你的代码可能会依赖于更具体的目标,例如 @opencv//:core

作为第三个选项,在你的 WORKSPACE 文件中声明 cmake 和 OpenCV,并使用 genrule 在 Bazel 中运行 OpenCV 上的 cmake。


1
非常感谢!我选择了最简单的选项(第一个)。如果有人使用OpenCV 3.1.0,需要进行一些小的更正:cc_library( name = "opencv", srcs = glob([ "lib/.so" ]), hdrs = glob([ "include/**/*.hpp" ]), includes = [ "include" ], visibility = [ "//visibility:public" ], linkstatic = 1, ) - John Zhang
@kristina 第二个解决方案也不具备可移植性。在运行cmake时会生成许多缺失的文件,而不仅仅是opencv_modules.hpp - Ghilas BELHADJ
@Ghilas 我认为你没有理解我所说的“可移植性”的含义:如果你的构建对你有效,那么你可以将其交给你的同事,它也可以在他们的机器上运行。如果构建没有暴露你需要的工件,那就不是可移植性问题。 - kris
@kristina,即使我的代码只需要@opencv/:core,但是opencv.BUILD中的代码并不能直接使用,这就是我的意思。我在这里找到了更完整的代码,现在我唯一需要的就是如何将OpenCV的JNI函数公开,因为我也要从Java中使用该库。有什么想法吗? - Ghilas BELHADJ
推荐使用 http_archive 而不是 git_repositorynew_git_repository。原因如下:Git 仓库规则依赖于系统的 git(1),而 HTTP 下载器内置于 Bazel 中,没有系统依赖。 http_archive 支持一系列 urls 作为镜像,而 git_repository 只支持单个 remotehttp_archive 可以与仓库缓存一起使用,但 git_repository 不行。最佳实践 - user0221441
显示剩余5条评论

7
以下是一种适用于当前版本bazel(v3.1.0)的最新解决方案。在此小项目中,我想构建一个依赖于最新的openCV版本(4.3.0)的C++程序,但只选择了一组模块(core,highgui,imgcodecs,imgproc)。
无需本地安装openCVbazel从github加载所需文件(即使已安装旧版本的openCV也可以正常工作): /WORKSPACE文件的内容:
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

all_content = """filegroup(name = "all", srcs = glob(["**"]), visibility = ["//visibility:public"])"""

http_archive(
    name = "opencv",
    build_file_content = all_content,
    strip_prefix = "opencv-4.3.0",
    urls = ["https://github.com/opencv/opencv/archive/4.3.0.zip"],
)

http_archive(
    name = "rules_foreign_cc",
    strip_prefix = "rules_foreign_cc-master",
    url = "https://github.com/bazelbuild/rules_foreign_cc/archive/master.zip",
)

load("@rules_foreign_cc//:workspace_definitions.bzl", "rules_foreign_cc_dependencies")

rules_foreign_cc_dependencies()

/BUILD文件的内容:

load("@rules_foreign_cc//tools/build_defs:cmake.bzl", "cmake_external")

cmake_external(
    name = "opencv",
    cmake_options = [
        "-GNinja",
        "-DBUILD_LIST=core,highgui,imgcodecs,imgproc",
    ],
    lib_source = "@opencv//:all",
    make_commands = [
        "ninja",
        "ninja install",
    ],
    out_include_dir = "include/opencv4",
    shared_libraries = [
        "libopencv_core.so",
        "libopencv_highgui.so",
        "libopencv_imgcodecs.so",
        "libopencv_imgproc.so",
    ],
    visibility = ["//visibility:public"],
)

最后,你需要依赖于opencv的目标文件,在我的情况下是文件/opencv/BUILD

cc_binary(
    name = "opencv",
    srcs = ["opencv.cpp"],
    data = [
      "LinuxLogo.jpg",
      "WindowsLogo.jpg",
    ],
    deps = ["//:opencv"],
)

如果您想尝试它,请转到以下链接: blackliner/automata

git clone https://github.com/blackliner/automata.git
cd automata
bazel build ...

尝试在 Windows 10 上使用 CMake 3.17.2 构建 Visual Studio 2019 Win64(即 cmake_options=[-G"Visual Studio 16 2019" -A"Win64"],make_commands = ["MSBuild.exe INSTALL.vcxproj"])。无法在 PowerShell 中工作。切换到 MSys2 shell - 也不起作用 - 我猜这是在 Linux 上测试的? - Vertexwahn
好的,等一下,CMake?这是关于使用Bazel而不是CMake。你到底想做什么?是的,我使用的是Ubuntu 18.04 LTS。 - Florian Berchtold
cmake_external 调用 CMake。我使用 Bazel 3.1.0 在 Windows 10 下进行了测试。但是由于它使用 bash 脚本,因此 cmake_external 目前无法在 Powershell 上工作。即使在 msys2 shell 上也会遇到问题... - Vertexwahn

3

我采用了 @kristina 提供的第一种选项,并且成功了。

  1. Install opencv:

    git clone https://github.com/Itseez/opencv.git
    
    cd opencv/
    
    mkdir build install
    
    cd build
    
    cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local ..
    
    make install
    
  2. Change WORKSPACE file (at tensorflow/WORKSPACE cloned from github)

    new_local_repository(
    
    name = "opencv",
    
    path = "/usr/local",
    
    build_file = "opencv.BUILD",
    
    )
    
  3. Make opencv.BUILD file at the same place as WORKSPACE file:

    cc_library(
    
    name = "opencv",
    
    srcs = glob(["lib/*.so*"]),
    
    hdrs = glob(["include/**/*.hpp"]),
    
    includes = ["include"],
    
    visibility = ["//visibility:public"], 
    
    linkstatic = 1,
    
    )
    
  4. You may have to config the opencv libs path:

确保你拥有/etc/ld.so.conf.d/opencv.conf文件,并且文件内容如下:

    /usr/local/lib
步骤 b: 运行以下命令:
    sudo ldconfig -v

我该如何在BUILD文件中包含int类型? - Pototo
确保也获取.h文件。不确定这对其他人是否有效。这是我的构建结果:package(default_visibility = ["//visibility:public"])cc_library( name = "opencv", srcs = glob(["lib/.so"]), hdrs = glob([ "include/opencv2//*.h", "include/opencv2//*.hpp", ]), strip_include_prefix = "include", linkstatic = 1, visibility = ["//visibility:public"], ) - tdeegan
哎呀,当我这样做时,仍然会得到大量未定义的引用。 在我的依赖项中,我添加了@opencv。如果我执行@opencv//:core,bazel会报错未定义。 - Nam Vu

1
这是我为OpenCV 2.4.13.2的core/所做的。这种方法来自于OpenCV源代码,该源代码是由@kristina的答案改编而来。
首先要添加opencv 2.4版本的http_archive:
# OpenCV 2.4.13.2
new_http_archive(
    name = "opencv2",
    url = "https://github.com/opencv/opencv/archive/2.4.13.2.zip",
    build_file = "third_party/opencv2.BUILD",
    strip_prefix = "opencv-2.4.13.2",
)

然后,将文件third_party/opencv2.BUILD添加为:

cc_library(
    name = "dynamicuda",
    hdrs = glob([
        "modules/dynamicuda/include/**/*.hpp",
    ]),
    includes = [
        "modules/dynamicuda/include"
    ],
)

cc_library(
    name = "core",
    visibility = ["//visibility:public"],
    srcs = glob(["modules/core/src/**/*.cpp"]),
    hdrs = glob([
        "modules/core/src/**/*.hpp",
        "modules/core/include/**/*.hpp",
     ]) + [
        ":module_includes",
        ":cvconfig",
        ":version_string",
    ],
    copts = [
        "-Imodules/dynamicuda/include",
    ],
    # Note that opencv core requires zlib and pthread to build.
    linkopts = ["-pthread", "-lz"],
    includes = [
        "modules/core/include",
    ],
    deps = [
        ":dynamicuda",
    ],
)

genrule(
    name = "module_includes",
    cmd = "echo '#define HAVE_OPENCV_CORE' > $@",
    outs = ["opencv2/opencv_modules.hpp"],
)

genrule(
    name = "cvconfig",
    outs = ["cvconfig.h"],
    cmd = """
cat > $@ <<"EOF"
// JPEG-2000
#define HAVE_JASPER

// IJG JPEG
#define HAVE_JPEG

// PNG
#define HAVE_PNG

// TIFF
#define HAVE_TIFF

// Compile for 'real' NVIDIA GPU architectures
#define CUDA_ARCH_BIN ""

// NVIDIA GPU features are used
#define CUDA_ARCH_FEATURES ""

// Compile for 'virtual' NVIDIA PTX architectures
#define CUDA_ARCH_PTX ""
EOF"""
)

genrule(
    name = "version_string",
    outs = ["version_string.inc"],
    cmd = """
cat > $@ <<"EOF"
"\\n"
)

请注意,我没有在 version_string.inc 中放置任何内容。它只是一个 C++ 字符串字面量,不会影响 OpenCV 的功能。如果您真的对该文件感兴趣,请参见此 example
在此之后,您应该能够添加具有依赖于 @opencv2//:core 的目标。

0

1
我在Windows 10 x64 + Powershell + Bazel 3.1.0上进行了测试 - linkstatic = 1 没有效果。我可以编译我的OpenCV代码,但运行时会抱怨缺少OpenCV DLL文件。 - Vertexwahn
如果出现DLL文件缺失的情况,最方便的方法是将OpenCV添加到Windows环境变量中。例如:打开环境变量列表->编辑“PATH”->添加[C:\opencv]/install/[x64]/[vc14]/bin;将OpenCV路径和VS版本替换为您的设置。 - JC Ju

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接