Environment: MAC machine, running my code inside virtual machine with guest OS: Ubuntu 14.4 LTS.
I am compiling openCV within tensorflow workspace under examples. My WORKSPACE and opencv.BUILD file look similar to the one mentioned here
My BUILD file for the opencv + tensorflow project looks like following:
package(default_visibility = ["//tensorflow:internal"])
licenses(["notice"]) # Apache 2.0
exports_files(["LICENSE"])
cc_binary(
name = "label_image",
srcs = [
"main.cc",
],
linkopts = ["-lm"],
copts = ["-DWITH_FFMPEG=OFF"],
deps = [
"//tensorflow/cc:cc_ops",
"//tensorflow/core:framework_internal",
"//tensorflow/core:tensorflow",
"#opencv//:opencv"
],
)
filegroup(
name = "all_files",
srcs = glob(
["**/*"],
exclude = [
"**/METADATA",
"**/OWNERS",
"bin/**",
"gen/**",
],
),
visibility = ["//tensorflow:__subpackages__"],
)
If i disable tensorflow dependences (and also comment the tensorflow related code). I can see that the webcam is captures properly. like this:
deps = [
#"//tensorflow/cc:cc_ops",
#"//tensorflow/core:framework_internal",
#"//tensorflow/core:tensorflow",
"#opencv//:opencv"
],
But if i still keep the code commented/uncommented and also keep the tensorflow dependences my webcam hangs at VideoCapture::read()
By default, opencv use FFMPEG codec and i tried enabling and disabling FFMPEG. Can someone please help me why when tensorflow library is compiled in the project makes my openCV read() hangs?
The OpenCV Bazel build configuration you linked above appears to just glob all the .so files that CMake built. Maybe you need to pass the -DWITH_FFMPEG=OFF cflag to CMake? If you pass it to Bazel as you did above, it's only going to apply to the compilation of main.cc.
Related
I have a project that builds via CMake and requires a lot of manual installations of additional deps. I want to migrate this project to Bazel and make these libs automatically downloadable. I found a solution for Boost, but I can't understand how to add icu4c and other libs which builds via other tools.
There are many ways to make use of third-party libraries using Bazel. The chosen approach depends on different properties of the third-party library, e.g.: Does the third-party library already support Bazel? Is the library available only as a pre-build package? Does the library use code generators, or any other tools, or transitive dependencies?
Given the example of {fmt} which uses CMake as build system you can proceed as the following:
First approach: Inject a BUILD file
In your WORKSPACE file you can do something like:
maybe(
new_git_repository,
name = "fmt",
branch = "master",
remote = "https://github.com/fmtlib/fmt",
build_file = "//third_party:fmt.BUILD",
)
The corresponding fmt.BUILD file can look like this:
cc_library(
name = "fmt",
srcs = [
#"src/fmt.cc", # No C++ module support
"src/format.cc",
"src/os.cc",
],
hdrs = [
"include/fmt/args.h",
"include/fmt/chrono.h",
"include/fmt/color.h",
"include/fmt/compile.h",
"include/fmt/core.h",
"include/fmt/format.h",
"include/fmt/format-inl.h",
"include/fmt/locale.h",
"include/fmt/os.h",
"include/fmt/ostream.h",
"include/fmt/printf.h",
"include/fmt/ranges.h",
"include/fmt/xchar.h",
],
includes = [
"include",
"src",
],
strip_include_prefix = "include",
visibility = ["//visibility:public"],
)
Advantages:
fmt-8.01 does not have out-of-the-box support for {fmt}. This way Bazel can make use of {fmt} without the need that {fmt} knows anything about Bazel
fmt-8.0.1 needs not to be modified
Disadvantages:
Reinvent the wheel: Every Bazel project that wants to use {fmt} has to reinvent this fmt.BUILD file.
Maintenance costs: If different Bazel projects want to adapt to future versions of {fmt} every single project has to do this maintenance by its own. Maybe new files will be introduced.
Missing Knowledge: Maybe for some reason, it makes sense to define some special defines upfront, etc. It also takes some time and knowledge of {fmt} to set up such a BUILD file. What is the best practice to build this lib?
Second approach: Bazelize {fmt}
Add a WORKSPACE file and BUILD file to the {fmt} repository.
This way {fmt} gets bazelized and can be used in your Bazel builds.
You could use it then this way:
Example
Create a WORKSPACE.bazel file with the following content:
load("#bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
# Fetch bazelized fmt
git_repository(
name = "fmt",
branch = "bazel-support", # A copy of master where BUILD.bazel, WORKSPACE.bazel, .bazelrc and .bazelversion are moved to root
remote = "https://github.com/<user_or_organisation>/fmt", # replace <user_or_organisation> by a valid account
)
Create a BUILD.bazel file and add a dependency to {fmt} (wit the content of fmt.BUILD).
In favor of keeping the {fmt} project directory clean, those files were not added to the project root directory (see here for details).
Third approach: Using the {fmt} repository with Bazel
Even though the {fmt} repository does not contain a WORKSPACE file in its root directory, there is an easy approach to use the {fmt} repository with Bazel out of the box. This is demonstrated in the following example.
Add to your WORKSPACE file:
load("#bazel_tools//tools/build_defs/repo:git.bzl", "new_git_repository")
# Fetch all files from fmt including the BUILD file `support/bazel/BUILD.bazel`
new_git_repository(
name = "fmt_workaround",
branch = "master",
remote = "https://github.com/fmtlib/fmt/",
build_file_content = "# Empty build file on purpose"
)
# Now the BUILD file `support/bazel/BUILD.bazel` can be used:
new_git_repository(
name = "fmt",
branch = "master",
remote = "https://github.com/fmtlib/fmt/",
build_file = "#fmt_workaround//:support/bazel/BUILD.bazel"
)
Create a BUILD.bazel file and add a dependency to {fmt}:
cc_binary( # Build a binary
name = "Demo", # Name of the binary
srcs = ["main.cpp"], # List of files - we only have main.cpp
deps = ["#fmt//:fmt"], # Depend on fmt
)
Make use of {fmt} in main.cpp:
#include "fmt/core.h"C
int main() {
fmt::print("The answer is {}.\n", 42);
}
The expected output of this example is The answer is 42.
Forth approach: Make use of patch_cmd
load("#bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
git_repository(
name = "fmt",
branch = "master",
patch_cmds = [
"mv support/bazel/.bazelrc .bazelrc",
"mv support/bazel/.bazelversion .bazelversion",
"mv support/bazel/BUILD.bazel BUILD.bazel",
"mv support/bazel/WORKSPACE.bazel WORKSPACE.bazel",
],
# Windows related patch commands are only needed in the case MSYS2 is not installed
patch_cmds_win = [
"Move-Item -Path support/bazel/.bazelrc -Destination .bazelrc",
"Move-Item -Path support/bazel/.bazelversion -Destination .bazelversion",
"Move-Item -Path support/bazel/BUILD.bazel -Destination BUILD.bazel",
"Move-Item -Path support/bazel/WORKSPACE.bazel -Destination WORKSPACE.bazel",
],
remote = "https://github.com/fmtlib/fmt",
)
More details here.
Other libraries
I have written a few blog posts about Bazelizing different libs:
Bazel: Bazelizing Qt5 for macOS
Bazel: Bazelizing Embree 3.13.0
Bazel: Bazelizing Qt5 & Qt6
Bazel: Handling external dependencies in OpenEXR
Bazel: Offical support for OpenEXR
Bazel: Bazelizing OpenEXR
Bazel: Bazelizing Embree 3.12.1
I am working on a c++ project with bazel BUILD system in the vscode IDE environment. To illustrate, one could take one of the large open source projects such as tensorflow.
While the intellisense functionality works very well for source/header dependencies within the project folder itself, vscode seems unable to recognize headers included from third_party/external dependencies, such as protobuf headers in the tensorflow project (see below screenshot). So is there a way for vscode to recognize such headers, with the help of both c++/clang and bazel plugins?
To provide more details:
This protobuf header is included by the following BAZEL target in tensorflow/lite/toco/BUILD,
cc_library(
name = "toco_port",
srcs = [
"toco_port.cc",
],
hdrs = [
"format_port.h",
"toco_port.h",
"toco_types.h",
],
deps = [
"//tensorflow/core:framework_lite",
"//tensorflow/core:lib",
"//tensorflow/core:lib_internal",
"#com_google_absl//absl/status",
"#com_google_protobuf//:protobuf_headers",
],
)
which in turn is defined by the following workspace rule in tensorflow/workspace2.bzl
tf_http_archive(
name = "com_google_protobuf",
patch_file = ["//third_party/protobuf:protobuf.patch"],
sha256 = "cfcba2df10feec52a84208693937c17a4b5df7775e1635c1e3baffc487b24c9b",
strip_prefix = "protobuf-3.9.2",
system_build_file = "//third_party/systemlibs:protobuf.BUILD",
system_link_files = {
"//third_party/systemlibs:protobuf.bzl": "protobuf.bzl",
"//third_party/systemlibs:protobuf_deps.bzl": "protobuf_deps.bzl",
},
urls = tf_mirror_urls("https://github.com/protocolbuffers/protobuf/archive/v3.9.2.zip"),
)
The downloaded external repository is usually stored in a local directory ~/.cache/_bazel, specified by the --output_user_root flag in bazel.
I am trying to use a locally built package (this one) within an existing bazel project. It bazel builds without any errors, but when I try to bazel run it, it immediately segfaults. I tried building it in debug mode, but when I run it in debug mode it still immediately segfaults without any useful error message.
I built the external package following the instructions in the README and the examples run fine (outside of bazel), so I know that the external libraries are not the issue.
I made a repository to access this package in my WORKSPACE file
new_local_repository(
name = "ApproxMVBB",
path = "/absolute/path/to/ApproxMVBB",
build_file = "approxmvbb.BUILD", )
The approxmvbb.BUILD file looks like this
cc_library(
name = "ApproxMVBB-lib",
srcs = glob(["**/*.a"])+glob(["**/*.so"]),
hdrs = glob(["**/*.hpp"]),
includes = ["include", "build/include", "external/Diameter/include", "external/GeometryPredicates/include"],
visibility = ["//visibility:public"],
)
And the cc_binary I am trying to run looks like this
cc_binary(
name = "TestMVBB",
srcs = [
"src/test_approxmvbb.cpp",
],
deps = [
"#ApproxMVBB//:ApproxMVBB-lib",
],
linkopts = ["-shared"],
)
The source code for the binary src/test_approvmvbb.cpp
#include <iostream>
#include "ApproxMVBB/ComputeApproxMVBB.hpp"
int main(int argc, char** argv)
{
ApproxMVBB::Matrix3Dyn points(3,10000);
points.setRandom();
ApproxMVBB::OOBB oobb = ApproxMVBB::approximateMVBB(points,0.001,500,5,0,5);
oobb.expandToMinExtentRelative(0.1);
return 0;
}
I found my mistakes. First, I was changing a lot of things and forgot to rebuild the external package, so the libraries didn't exist... oops.
But more importantly, when the external package is built, it outputs library files that have file extensions other than .o and .so so I had to change the following line in the cc_library target
srcs = glob(["**/*.a"])+glob(["**/*.so"])+glob(["**/*.so.2.1.1"]),
Hope this helps someone in the future!!
I'm building a simple C++ application on macOS with Bazel. I want to use OpenCV in my application. I installed OpenCV with brew install opencv and I followed Building OpenCV code using Bazel to create my setup.
In my WORKSPACE file, I have:
new_local_repository(
name = "opencv",
path = "/usr/local/opt/opencv",
build_file = "opencv.BUILD",
)
In my opencv.BUILD file, I have:
cc_library(
name = "opencv",
srcs = glob(["lib/*.dylib"]),
hdrs = glob(["include/opencv4/opencv2/**/*.h*"]),
includes = ["include/opencv4"],
visibility = ["//visibility:public"],
linkstatic = 1,
)
In my BUILD file, I have:
cc_library(
name = "lib",
srcs = ["hello.cpp"],
deps = [
"#opencv//:opencv",
],
)
This works as long as the opencv target takes the OpenCV .dlyb files (srcs = glob(["lib/*.dylib"])).
But now I want to build the OpenCV libraries statically into my binary. When I change the opencv target to take OpenCV's .a files (srcs = glob(["lib/*.a"])), I get a bunch of Undefined symbols errors about AVFoundation classes. In my code I use the OpenCV Capture API (which I assume uses AVFoundation under the hood), so this sorta makes sense, but I'm not sure how to fix it.
How should I configure my Bazel targets to build OpenCV statically into my binary?
I am writing a sample C++ project that uses Bazel to serve as an example idiom for other collaborators to follow.
Here is the repository: https://github.com/thinlizzy/bazelexample
I am interested to know if I am doing it 'right', more specifically about this file: https://github.com/thinlizzy/bazelexample/blob/38cc07931e58ff5a888dd6a83456970f76d7e5b3/demo/BUILD
when regarding to pick particular implementations.
cc_library(
name = "demo",
srcs = ["demo.cpp"],
deps = [
"//example:frontend",
],
)
cc_binary(
name = "main_win",
deps = [
":demo",
"//example:impl_win",
],
)
cc_binary(
name = "main_linux",
deps = [
":demo",
"//example:impl_linux",
],
)
Is this following a correct/expected idiom for Bazel projects? I am doing this way already for other projects, by concentrating all the platform-specific dependencies in separate targets and then the binaries just depend on them.
Someone in bazel-discuss list told me to use select, instead, but my attempts failed to 'detect' the operating system. I'm sure I did something wrong, but the lack of info and examples don't tell me much how to use it properly.
#bazel_tools contains predefined platform conditions:
$ bazel query #bazel_tools//src/conditions:all
#bazel_tools//src/conditions:windows_msys
#bazel_tools//src/conditions:windows_msvc
#bazel_tools//src/conditions:windows
#bazel_tools//src/conditions:remote
#bazel_tools//src/conditions:host_windows_msys
#bazel_tools//src/conditions:host_windows_msvc
#bazel_tools//src/conditions:host_windows
#bazel_tools//src/conditions:freebsd
#bazel_tools//src/conditions:darwin_x86_64
#bazel_tools//src/conditions:darwin
You can use them directly in the BUILD file:
cc_library(
name = "impl",
srcs = ["Implementation.cpp"] + select({
"#bazel_tools//src/conditions:windows": ["ImplementationWin.cpp"],
"#bazel_tools//src/conditions:darwin": ["ImplementationMacOS.cpp"],
"//conditions:default": ["ImplementationLinux.cpp"],
}),
# .. same for hdrs and data
)
cc_binary(
name = "demo",
deps = [":impl"],
)
See the documentation for select for details on the syntax.
Add a .bazelrc to your project. Add the lines build:vs2019 --cxxopt=/std:c++14 and build:gcc --cxxopt=-std=c++14. Build your code bazel build --config=msvc //... or bazel build --config=gcc //....
#Vertexwahn's answer caused some confusion on my end, so I hope this answer helps clarify a bit. While his answer does not directly tie into the question, it may be of use to others trying to build on entirely different platforms without file specific inclusions.
Here is a link to where I answered that particular question: How do I specify portable build configurations for different operating systems for Bazel?