17

What is the best way to build C++ code that uses the OpenCV library using Bazel? I.e., what would the BUILD rules look like?

How should be the WORKSPACE and BUILD files look like in order to compile the following code using 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
  • I don't see why this was closed for looking for offsite resources... it isn't. Commented Jan 28, 2021 at 15:52

5 Answers 5

35

There are a couple of options. The easiest way is probably to install locally in the way the OpenCV site recommends:

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

Then add the following to your WORKSPACE file:

new_local_repository(
    name = "opencv",
    path = "/path/to/opencv/install",
    build_file = "opencv.BUILD",
)

Create opencv.BUILD in the same directory as WORKSPACE with the following:

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

Then your code can depend on @opencv//:opencv to link in the .so's under lib/ and reference the headers under include/.

However, this isn't very portable. If you want a portable solution (and you're feeling ambitious), you could add the OpenCV git repo to your workspace and download & build it. Something like:

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

And make opencv.BUILD something like:

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"],
)

...

Then your code could depend on more specific targets, e.g., @opencv//:core.

As a third option, you declare both cmake and OpenCV in your WORKSPACE file and use a genrule to run cmake on OpenCV from within Bazel.

Sign up to request clarification or add additional context in comments.

10 Comments

Thanks so much! I went with the easiest option (the first one). Some minor corrections if anyone is using OpenCV 3.1.0: cc_library( name = "opencv", srcs = glob([ "lib/*.so*" ]), hdrs = glob([ "include/**/*.hpp" ]), includes = [ "include" ], visibility = [ "//visibility:public" ], linkstatic = 1, )
@kristina the second solution is not portable neither. there is a lot of missing files that are generated when running cmake, not only opencv_modules.hpp
@Ghilas I think you are missing what I meant by "portable:" if your build works for you, you can hand it to your coworker and it'll work on their machine, too. If the build doesn't expose the artifacts you need, it's not a portability problem.
@kristina The code in opencv.BUILD don't work as is, even if my code only needs @opencv/:core, that's what I meant. I've found a more complete code here that works. Now the only thing that I'm looking for is how to expose the JNI functions of OpenCV as I use the library from Java too. Any Idea ?
@kristina on mac I'm getting a linker error like this. Any idea? Undefined symbols for architecture x86_64: "cv::Mat::deallocate()", referenced from ...
|
7

Here is an up2date solution that works with the current set of bazel(v3.1.0). In this little project i wanted to build a C++ program that depends on the newest openCV release (4.3.0), but only on a selected set of modules (core,highgui,imgcodecs,imgproc).

No local installed openCV required, bazel loads the needed files from github (although it works even when there is an old version of openCV installed):

Content of /WORKSPACE file:

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()

Content of /BUILD file:

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"],
)

And finally, your target that depends on opencv, in my case a file /opencv/BUILD:

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

If you want to try it out, here is the rest: blackliner/automata

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

3 Comments

Tried to use it under Windows 10 with CMake 3.17.2 building for Visual Studio 2019 Win64 (i.e. cmake_options=[-G"Visual Studio 16 2019" -A"Win64"], make_commands = ["MSBuild.exe INSTALL.vcxproj"]). Does not work with PowerShell. Switched to MSys2 shell - does also not work - I guess this was tested using Linux?
Ok, wait, CMake? This is about using Bazel instead of CMake. What exactly did you try to do? And yes, i used Ubuntu 18.04 LTS.
cmake_external calls CMake. I used Bazel 3.1.0 to test it under Windows 10. But cmake_external works currently not for Powershell since it uses bash scripts. Even on msys2 shell I run into problems...
3

I succeed with @kristina's first option.

  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:

a. Make sure you have /etc/ld.so.conf.d/opencv.conf file with content:

    /usr/local/lib

b. Run the command:

    sudo ldconfig -v

3 Comments

How do I include int my BUILD file?
Make sure to get the .h files too. Not sure how this worked for others. This is what my build looked like: 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"], )
Humm, when I do this i'm still getting tons on undefined reference/ In my deps, I added @opencv. if I do @opencv//:core bazel cries with not defined
1

This is what I did for OpenCV 2.4.13.2, core/ only. This approach goes from the opencv source, which is adapted from the accepted answer above by @kristina.

The first thing is to add the http_archive for the opencv 2.4 release:

# 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",
)

And then, add the file third_party/opencv2.BUILD as:

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"
)

Note that I did not put anything in the version_string.inc. It is just a C++ string literal which does not affect the functionality of OpenCV. If you are really interested in this file see this example.

After this you should be able to add target with dependencies on @opencv2//:core.

Comments

0

Here's a simple demo of OpenCV & C++ built with Bazel: https://github.com/jcju/opencv_bazel_win

You may set up the OpenCV path in WORKSPACE and run:

bazel run //src:main

2 Comments

I tested it on Window 10 x64+ Powershell + Bazel 3.1.0 - linkstatic = 1 has no effect. I can compile my OpenCV code, but when running it complains about mission OpenCV DLLs.
If it shows missing of DLLs, the most convenient way is to add opencv into Windows Environment Variables. For example: open Environment Variables list -> Edit "PATH"-> add [C:\opencv]/install/[x64]/[vc14]/bin; replace the opencv path and VS version with your settings.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.