如何使用 Bazel 构建项目使用 OpenCV [关闭]

Posted

技术标签:

【中文标题】如何使用 Bazel 构建项目使用 OpenCV [关闭]【英文标题】:How to use Bazel to build project uses OpenCV [closed] 【发布时间】:2016-01-25 02:38:58 【问题描述】:

使用 Bazel 构建使用 OpenCV 库的 C++ 代码的最佳方法是什么?即,BUILD 规则是什么样的?

WORKSPACEBUILD 文件应该是什么样子才能使用 bazel 编译以下代码:


#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;


【问题讨论】:

我不明白为什么为了寻找异地资源而关闭它......不是。 【参考方案1】:

有几个选项。最简单的方法可能是按照 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 repo 添加到您的工作区并下载并构建它。类似的东西:

# 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。

【讨论】:

非常感谢!我选择了最简单的选项(第一个)。如果有人使用 OpenCV 3.1.0,请进行一些小的更正: cc_library( name = "opencv", srcs = glob([ "lib/*.so*" ]), hdrs = glob([ "include/**/*.hpp " ]), 包括 = [ "include" ], 可见性 = [ "//visibility:public" ], linkstatic = 1, ) @kristina 第二种解决方案也不是可移植的。运行cmake的时候有很多丢失的文件,不仅仅是opencv_modules.hpp @Ghilas 我认为你错过了我所说的“便携式”:如果你的构建适合你,你可以把它交给你的同事,它也可以在他们的机器上工作。如果构建没有公开您需要的工件,则不是可移植性问题。 @kristina opencv.BUILD 中的代码不能按原样工作,即使我的代码只需要 @opencv/:core,这就是我的意思。我找到了一个更完整的代码here 可以工作。现在我唯一要寻找的是如何在我使用 Java 库时公开 OpenCV 的 JNI 函数。有什么想法吗? @kristina on mac 我收到这样的链接器错误。任何的想法? Undefined symbols for architecture x86_64: "cv::Mat::deallocate()", referenced from ...【参考方案2】:

这是一个更新的解决方案,适用于当前的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 测试的? 好的,等等,CMake?这是关于使用 Bazel 而不是 CMake。你到底想做什么?是的,我使用的是 Ubuntu 18.04 LTS。 cmake_external 调用 CMake。我使用 Bazel 3.1.0 在 Windows 10 下对其进行测试。但 cmake_external 目前不适用于 Powershell,因为它使用 bash 脚本。即使在 msys2 shell 上我也遇到了问题......【参考方案3】:

@kristina 的第一个选项我成功了。

    安装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
    

    更改 WORKSPACE 文件(在 tensorflow/WORKSPACE 从 github 克隆)

    new_local_repository(
    
    name = "opencv",
    
    path = "/usr/local",
    
    build_file = "opencv.BUILD",
    
    )
    

    将 opencv.BUILD 文件与 WORKSPACE 文件放在同一位置:

    cc_library(
    
    name = "opencv",
    
    srcs = glob(["lib/*.so*"]),
    
    hdrs = glob(["include/**/*.hpp"]),
    
    includes = ["include"],
    
    visibility = ["//visibility:public"], 
    
    linkstatic = 1,
    
    )
    

    您可能需要配置 opencv 库路径:

一个。确保你有 /etc/ld.so.conf.d/opencv.conf 文件的内容:

    /usr/local/lib

b.运行命令:

    sudo ldconfig -v

【讨论】:

如何在我的 BUILD 文件中包含 int? 确保也获取 .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" ], ) 嗯,当我这样做时,我仍然会收到大量未定义的引用/在我的部门中,我添加了@opencv。如果我这样做 @opencv//:core bazel 哭泣没有定义【参考方案4】:

这是我为 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 中添加任何内容。它只是一个不影响 OpenCV 功能的 C++ 字符串文字。如果你真的对此文件感兴趣,请查看example。

在此之后,您应该能够添加依赖于 @opencv2//:core 的目标。

【讨论】:

【参考方案5】:

这是一个使用 Bazel 构建的 OpenCV 和 C++ 的简单演示:https://github.com/jcju/opencv_bazel_win

您可以在 WORKSPACE 中设置 OpenCV 路径并运行:

bazel run //src:main

【讨论】:

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

以上是关于如何使用 Bazel 构建项目使用 OpenCV [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

如何使用vscode python调试器来调试用bazel构建的项目?

Bazel简介:构建C ++项目

一文学会使用Bazel构建C++项目

一文学会使用Bazel构建C++项目

一文学会使用Bazel构建C++项目

一文学会使用Bazel构建C++项目