Bazel build with OpenCV 3.3 dependencies - c++

I'm trying to use Bazel to compile and distribute an OpenCV based C++ code and I'm facing an issue I can't resolve.
I build and install OpenCV 3.3 from sources, on an Ubuntu 16.04 LTS, with CUDA support (CUDA 8). I install it in the standard directory /usr/local.
Given it, I created my project with this WORKSPACE file :
new_local_repository(
name = "opencv",
path = "/usr/local",
build_file = "opencv.BUILD",
)
The opencv.BUILD contains :
cc_library(
name = "opencv",
srcs = glob(["lib/*.so*"]),
hdrs = glob(["include/**/*.hpp"]),
includes = ["include"],
visibility = ["//visibility:public"],
linkstatic = 1,
)
And I can use it in my own code using :
cc_binary(
name = "main",
srcs = ["main.cc"],
deps = [
"#opencv//:opencv"
],
)
but some source files in OpenCV, as :
/usr/local/include/opencv2/flann/flann_base.hpp
includes headers file from the same directory, like :
#include "general.h"
And when I build with Bazel, I get this error :
ERROR: /home/damien/main/BUILD:1:1: C++ compilation of rule '//main:main' failed (Exit 1)
In file included from external/opencv/include/opencv2/flann.hpp:48:0,
from external/opencv/include/opencv2/opencv.hpp:62,
from main/main.cc:1:
external/opencv/include/opencv2/flann/flann_base.hpp:38:21: fatal error: general.h: No such file or directory
(general.h is in the same directory as flann_base.hpp).
If I rewrite the #include directive as :
#include "opencv2/flann/general.h"
It compiles well. But this is not a convenient solution.
So my question is : is there a way to tell Bazel to look for headers in the same directory as the "current" file in this library ? I look upon every C++ directives of Bazel, but I don't see anything to achieve it.
Thank you in advance.

Ok, shame on me. I have to import *.h :
cc_library(
name = "opencv",
srcs = glob(["lib/*.so*"]),
hdrs = glob(["include/**/*.hpp", "include/**/*.h"]),
includes = ["include"],
visibility = ["//visibility:public"],
linkstatic = 1,
)

In my case using opencv4 and Damien setup I was getting the error while including highgui.hpp:
external/opencv/include/opencv4/opencv2/highgui.hpp:46:10: fatal
error: opencv2/core.hpp: No such file or directory #include
"opencv2/core.hpp"
I could fix it adjusting the includes adding opencv4:
cc_library(
name = "opencv",
srcs = glob(["lib/*.so*"]),
hdrs = glob(["include/**/*.hpp", "include/**/*.h"]),
includes = ["include/opencv4"],
visibility = ["//visibility:public"],
linkstatic = 1,
)

Related

Include a header file from a third party package to a C++ code in my project

I am trying to include a header file from a third party package to a C++ code in my project. This is how I structured it:
main_repo/
- third_party/some_lib/
- BUILD
- header_file.h
- extensions/my_project/
- BUILD
- my_app.cpp
- my_app.hpp
main_repo/extensions/my_project/BUILD
cc_library(
name = "my_app",
srcs = ["my_app.cpp"],
hdrs = ["my_app.hpp"],
visibility = ["//visibility:public"],
deps = [
"//third_party/some_lib:some_lib",
],
)
main_repo/third_party/some_lib/BUILD
cc_library(
name = "some_lib",
hdrs = glob(["*.h"]),
includes = ["."],
visibility = ["//visibility:public"],
)
main_repo/extensions/my_project/my_app.hpp
// some code here
#include "header_file.h"
// some code here
I see
header_file.h: No such file or directory
error when I try building it. Do you see a problem with my approach?

How to properly link the QT library during bazel build compilation?

I am working on extending a project using bazel to build. However, one of my thrid_party dependency relying on a dynamic linked QT library. And I had a hard time linking it.
My project base is envpool, and I am using procgen as my third-party dependency. However, procgen relies on a series of QT library.
My approachs so far:
In the WorkSpace file, I specify the local directory of the qt library. (I am working on a new EC2 instance of Ubuntu 20.04 LTS on amazon cloud, and install qt5 and other base tools)
// download the github project
maybe(
http_archive,
name = "procgen",
sha256 = "8d443b7b8fba44ef051b182e9a87abfa4e05292568e476ca1e5f08f9666a1b72",
strip_prefix = "procgen-0.10.7/procgen/src/",
urls = [
"https://github.com/openai/procgen/archive/refs/tags/0.10.7.zip"
]
build_file = "//third_party/procgen:procgen.BUILD",
)
new_local_repository(
name = "qt",
path = "/usr/include/x86_64-linux-gnu/qt5", // I check indeed the header files are there
build_file = "BUILD.qt"
)
And the BUILD.qt file is
cc_library(
name = "qt_core",
hdrs = glob(["QtCore/**"]),
includes = ["."],
linkopts = [
"-lQt5Core",
],
visibility = ["//visibility:public"],
)
cc_library(
name = "qt_widgets",
hdrs = glob(["QtWidgets/**"]),
includes = ["."],
deps = [":qt_core"],
linkopts = [
"-lQt5Widgets",
],
visibility = ["//visibility:public"],
)
cc_library(
name = "qt_gui",
hdrs = glob(["QtGui/**"]),
includes = ["."],
deps = [":qt_core"],
linkopts = [
"-lQt5Gui",
],
visibility = ["//visibility:public"],
)
And the BUILD file for the procgen is
package(default_visibility = ["//visibility:public"])
cc_library(
name = "procgen",
srcs = glob(["*.cpp", "games/*.cpp"]),
hdrs = glob(["*.h"]),
deps = [
"#qt//:qt_widgets",
"#qt//:qt_gui",
"#qt//:qt_core",
]
)
However, when I use Bazel to build the project, it gives back the error that
Use --sandbox_debug to see verbose messages from the sandbox
In file included from external/procgen/games/starpilot.cpp:2:
external/procgen/games/../assetgen.h:10:10: fatal error: QColor: No such file or directory
10 | #include <QColor>
| ^~~~~~~~
compilation terminated.
I know I probably mess up the path or header file's include somewhere. For example, I am basically follow this post to include the QT library in the project, but I notice that guys use the full path "#include <qt/QTWidgets/xxxx>" instead. But I cannot change the code for "include" in the procgen.
This is the first time I use bazel, and on such a big project. Really appreciate if someone could help me out.
I put my current whole project package at here for reproducibility. You can use short-cut "sudo make bazel-build" to build it.
Best,
YJ

The hdrs of cc_library seems not working of Bazel

I'm working on a project, which depends on a third party project, let's say project E, which is a precompiled libraries. I've set a new repository_rule and invoked it in the workspace.bzl, and in the BUILD of the project E, the corresponding library rule has been set like following:
cc_library(
name = "e_lib",
srcs = [
"#e//:e_lib1",
"#e//:e_lib2",
],
hdrs = ["#e//:e_headers"],
visibility = ["//visibility:public"],
)
And the target e_lib1, e_lib2 and e_headers are defined in the file e.BUILD, and it is correctly symblo linked to the downloaded contents folder in the last part of implementation function of repository_rule.
The e.BUILD is something like:
filegroup(
name = "e_headers",
srcs = glob(["include/*"]),
visibility = ["//visibility:public"],
)
filegroup(
name = "e_lib1",
srcs = if_darwin(["lib/lib1.dylib"])
+ if_linux_x86_64(["lib/lib1.so"]),
visibility = ["//visibility:public"],
)
filegroup(
name = "e_lib2",
srcs = if_darwin(["lib/lib2.dylib"])
+ if_linux_x86_64(["lib/lib2.so"]),
visibility = ["//visibility:public"],
)
Let's say there is a header baz.h in the directory include of the project E.But during the building phase, an error, baz.h file not found, occurred when bazel tried to compile a file core.cc. The pseudocodes are something like:
// core.cc
#include "core.h"
...
// core.h
#include "im.h"
...
// im.h
#include "baz.h"
// This file doesn't have the corresponding
// .cc file since all the implementations
// are put in this header.
The dependency of these files is core.cc -> core.h -> im.h -> baz.h, and the building rule of core.cc is:
cc_library(
name = "core",
srcs = [
"core.cc",
],
hdrs = "core.h",
deps = [
"//third_party/E:e_lib"],
alwayslink = 1,
)
So is there something wrong with my BUILD file? I guess that maybe the core.cc doesn't directly depend on the e_lib, so the deps of it is actually useless. Should I build a cc_library for the im.h?

Glob not found in bazel

I am currently using Bazel to build a C++ project. Here is my WORKSPACE file:
cc_library(
name = "Boost",
srcs = glob(["/usr/local/lib/libboost*.so"]),
hdrs = glob(["/home/duttama/boost_1_55_0/**/*.h"]),
)
cc_library(
name = "OpenCV",
srcs = glob(["/usr/lib/x86_64-linux-gnu/libopencv*.so"]),
hdrs = glob(["/home/duttama/opencv-2.4.13/**/*.h"]),
)
cc_library(
name = "AffectivaSources",
srcs = glob(["/root/affdex-sdk/lib/*.so"]),
hdrs = glob(["/root/affdex-sdk/include/*.h"]),
)
And here is my BUILD file:
cc_binary(
name = "video-demo",
srcs = ["video-demo.cpp"],
deps = ["//lib:OpenCV",
"//lib:AffectivaSources",
"//lib:Boost",
],
)
When I run it, I get this error:
ERROR: /root/sdk-samples/WORKSPACE:17:12: Traceback (most recent call last):
File "/root/sdk-samples/WORKSPACE", line 15
cc_library(name = "AffectivaSources", srcs = ..."]), ..."]))
File "/root/sdk-samples/WORKSPACE", line 17, in cc_library
glob
name 'glob' is not defined
My question is why is it not finding the glob function. I am not sure what else to specify in the WORKSPACE file or how to import this glob function.
The WORKSPACE file is not meant for cc_binary/cc_rules; it's for defining project-wide rules such as external dependencies, and the glob function is not available in WORKSPACE files. See https://docs.bazel.build/versions/master/be/workspace.html for WORKSPACE rules.
It seems like you're importing c++ dependencies into your project: check out the new_local_repository rule here. This allows you to point to a folder in your local system. It will require you to write BUILD files containing the respective cc_library rules for each external dependency.
For example, in your WORKSPACE file:
new_local_repository(
name = "affectivalibrary",
path = "/root/affdex-sdk/",
build_file = "BUILD.affectiva",
)
and in your project, create a BUILD.affectiva:
cc_library(
name = "aff",
srcs = glob(["lib/*.so"]),
hdrs = glob(["include/*.h"]),
)
Once you've done this, you can depend on them in your BUILD files with the syntax:
cc_binary(
name = "video-demo",
srcs = ["video-demo.cpp"],
deps = ["#affectivalibrary//:aff", ...]
)
I'm also seeing that you are using absolute file paths in the srcs/hdrs attributes - glob patterns cannot be absolute. Please refer to the BUILD file target label syntax here: https://docs.bazel.build/versions/master/build-ref.html#lexi
If you're still confused, there's an example c++ project in the Bazel repository: https://github.com/bazelbuild/bazel/tree/master/examples/cpp

"ambiguous symbol" in Bazel building C++

Background
I am on Windows building with Bazel using cl to compile C++.
Subset of files:
third_party/icu/source/common/unicode/schriter.h
third_party/icu/source/common/unicode/utypes.h
third_party/icu/source/common/unicode/stringpiece.h
third_party/icu/source/common/stringpiece.cpp
third_party/icu/BUILD
a/a.cc
a/a.h
a/BUILD
b/cpp/src/strings/stringpiece.h
b/cpp/src/util/uri_utils.h
b/BUILD
schriter.h has #include "unicode/utypes.h".
uri_utils.h and b/cpp/src/strings/stringpiece.h both have class StringPiece. third_party/icu/source/common/unicode/stringpiece.h has class U_COMMON_API StringPiece : public UMemory
a.cc refers to StringPiece and has these includes:
#include "b/cpp/util/uri_utils.h"
#include "strings/stringpiece.h"
#include "third_party/icu/source/common/unicode/schriter.h"
a/BUILD:
cc_library(
name = "a",
srcs = ["a.cc"],
hdrs = ["a.h"],
deps = [
"//third_party/icu:common",
"//b:sdk_strings",
],
)
b/BUILD:
cc_library(
name = "sdk_strings",
srcs = [
"cpp/util/uri_utils.cc",
"cpp/src/strings/stringpiece.cc"
],
hdrs = [
"cpp/util/uri_utils.h",
"cpp/src/strings/stringpiece.h",
],
includes = ["cpp/src"],
)
third_party/icu/BUILD:
cc_library(
name = "common",
srcs = [
"source/common/stringpiece.cpp",
"source/stubdata/stubdata.c",
],
hdrs = glob(["**/*.h"]),
)
Problem
As is, building third_party/icu:common fails with:
third_party/icu/source/stubdata/stubdata.c(20): fatal error C1083: Cannot open include file: 'unicode/utypes.h': No such file or directory
If I add copts = ["/Ithird_party/icu/source/common",], to third_party/icu/BUILD, then icu:common builds but target a fails with:
third_party/icu/source/common/unicode/schriter.h(21): fatal error C1083: Cannot open include file: 'unicode/utypes.h': No such file or directory
If instead I add includes = ["source/common",],, then icu:common builds but target a fails with:
a/a.cc(168): error C2872: 'StringPiece': ambiguous symbol
b/cpp/util/uri_utils.h(24): note: could be 'StringPiece'
third_party\icu\source\common\unicode/stringpiece.h(52): note: or 'icu_54::StringPiece'
The source compiles fine using cmake, so I shouldn't need to change the source. How do I change the BUILD files to make this build correctly? How do I let everything in icu access the headers in unicode, but not expose unicode/stringpiece.h to targets that depend on icu?
You should be able to add the namespace (icu::StringPiece, I'm guessing?) to resolve the C2872 error.
For limiting visibility, check out the documentation:
For cc_library rules, headers in hdrs comprise the public interface of the library and can be directly included both from the files in hdrs and srcs of the library itself as well as from files in hdrs and srcs of cc_* rules that list the library in their deps. Headers in srcs must only be directly included from the files in hdrs and srcs of the library itself.
This means that hdrs define transitively visible headers and srcs is for "private" headers.
However, as the docs points out further down, this cannot always be perfectly enforced:
Unfortunately Bazel currently cannot distinguish between direct and transitive inclusions, so it cannot detect error cases where a file illegally includes a header directly that is only allowed to be included transitively. For example, Bazel would not complain if in the example above foo.cc directly includes baz.h. This would be illegal, because foo does not directly depend on baz.
So, it should prevent all but the most determined user to put it in the srcs of a private target with a copts = ['-Ithird_party/icu/source/common'] option.