Bazel build: dependency parameterized by command line - c++

I have a project for a plugin in C/C++ where I have different implementations and I would like to be able to select which implementation to use when building.
WORKSPACE
plugin/
BUILD
plugin.c
plugin.h
plugin_impl1/
BUILD
...
plugin_impl2/
BUILD
...
plugin_impl1/BUILD:
cc_library(
name = "plugin_impl1"
srcs = [...]
hdrs = [...]
)
plugin_impl2/BUILD:
cc_library(
name = "plugin_impl2"
srcs = [...]
hdrs = [...]
)
I want to know how to write plugin/BUILD so that I could write something like:
bazel build //plugin --which plugin_impl2
The executable name should always be the same so having multiple rules with different target names (for plugin) is not an option.

Related

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

Do not mangle name of shared library with Bazel

Given a C++ application, built with Bazel, that depends on an external, system provided shared library:
cc_binary(
name = 'app',
srcs = ['app.cpp'],
linkstatic = False,
deps = ['#my_system//:system_lib'],
)
The WORKSPACE and BUILD.my_system files:
new_local_repository(
name = 'my_system',
build_file = 'BUILD.my_system',
path = '/usr/lib/my_system/',
)
cc_import(
name = 'system_lib',
shared_library = 'system_lib.so',
visibility = ['//visibility:public'],
)
This builds, but first copies the system provided lib to the cache, and links to that:
$ ldd bazel-bin/app/app
system_lib.so => /home/erenon/bazel/proj/bazel-bin/app/../_solib_k8/_U#my_system_S_S_Csystem_Ulib___Uexternal_Smy_system/system_lib.so
[...]
If I move app to an identical system that has /usr/lib/my_system/system_lib.so, it breaks, as it misses the cache. I'd like to package app in a way that it directly links to the original .so, without the intermediate cache copy or name mangling, i.e: I'd like to achieve:
$ ldd bazel-bin/app/app
system_lib.so => /usr/lib/my_system/system_lib.so
[...]
I tried cc_import.system_provided, but that appears only work for Windows lib/dlls.
Wrap your library with another cc_library.
I can't explain why it works, but it does.
cc_library(
name = "libsystem_lib",
srcs = [ ":system_lib" ],
hdrs = ...
)
Depend on this one instead.

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

llvm: dyld: Symbol not found: __ZN4llvm11RuntimeDyld13MemoryManager6anchorEv

I am playing with LLVM and I hit an issue when trying to use JIT. I was able to build a compiler, it can be compiled, linked and it runs correctly (it compiles my toy programs). However, when I am trying to use build a JIT, it fails.
dyld: Symbol not found: __ZN4llvm11RuntimeDyld13MemoryManager6anchorEv
Referenced from: /Users/gruszczy/Projects/shwifty/./bazel-bin/_solib_darwin//liblibjit.so
Expected in: flat namespace
in /Users/gruszczy/Projects/shwifty/./bazel-bin/_solib_darwin//liblibjit.so
Abort trap: 6
I use Bazel to build everything, these are my build rules:
new_local_repository(
name = "llvm",
path = "/opt/local/libexec/llvm-4.0",
build_file= "llvm.BUILD")
cc_library(
name = "main",
srcs = glob(["lib/*.a"]),
hdrs = glob(["include/**/*.*"]),
visibility = ["//visibility:public"],
copts = ["-Iexternal/llvm/include"],
)
I use JIT in tests (I generate IR in the test then jit it, then run the method to see if it worked).
cc_library(
name = "jit",
srcs = ["jit.cc"],
hdrs = ["jit.h"],
deps = [
":ast",
":common",
"#llvm//:main"
],
copts = GENERAL_COPTS)
cc_test(
name = "codegen_test",
srcs = ["codegen_test.cc"],
deps = [
":ast",
":jit",
":lexer",
":parser",
":codegen",
"#gtest//:main",
"#llvm//:main"
],
copts = TEST_COPTS,
data = [":examples"],
size = "small"
)
Any suggestions what I might be missing?
The source of confusion is that Bazel by default links binaries statically, but tests dynamically. This makes the test-code-refactor loop faster, because changes to the test code only trigger the rebuild of the test, not the whole application. It can be disabled by setting linkstatic = 1 on codegen_test target.
As to why the symbols are not present in codegen_test when built as a shared library, that's much harder question and would need more project-specific information. But a possible solution might be to mark targets producing VMRuntimeDyld.a and VMMCJit.a as alwayslink = 1.
For the completeness, here's the link to an issue you reported on bazel.