How to link a library build using make rule in bazel - c++

I have built a lib.so using make rule in bazel. How do I link this external lib.so to a regular cc_library rule. I tried adding it in deps, but the guide suggests that deps can have cc_library or objc_library targets.
Also, do I need to pass any specific linking options, and how can I read more about them?

In the BUILD file, create a cc_library target that imports the built lib.so for other cc_library targets to depend on:
cc_library(
name = "lib",
srcs = ["lib.so"],
linkopts = ["...", "..."],
)
See the documentation on C++ use cases for more information.

Related

Package transitive deps in Bazel

I would like to package lets say a binary with the pkg_tar command. But I would also automatically like it to include all deps to that binary, for example all .so files from other Bezel targets that are referenced with deps. Is it possible?
pkg_tar(
name = "example",
srcs = ["//myprogram"], # This only packages myprogram target
mode = "0644",
)
Currently, this feature isn't officially supported. You have three basic options:
explicitly enumrate all deps
use one of "hacks" from https://github.com/bazelbuild/bazel/issues/1920
use undocumented include_runfiles = True feature https://github.com/bazelbuild/rules_pkg/issues/145
Setting the (undocumented) include_runfiles = True will include the shared object and any other runfiles of all the transitive dependencies.

Why does bazel not see includes defined in bazelrc?

I am migrating large legacy makefiles project to Bazel. Project used to copy all sources and headers into single "build dir" before build, and because of this all source and header files use single level includes, without any prefix (#include "1.hpp").
Bazel requires that modules (libraries) use relative path to header starting at WORKSPACE file, however my goal is to introduce Bazel build files, which require 0 modifications of a source code.
I use bazelrc to globally set paths to includes as if structure was flat:
.bazelrc:
build --copt=-Ia/b/c
/a/b/BUILD
cc_library(
name = "lib",
srcs = ["c/1.cpp"],
hdrs = ["c/1.hpp"],
visibility = ["//visibility:public"]
)
When I build this target, I see my -I flag in compiler invocation, but compilation fails because bazel can not find header 1.hpp:
$ bazel build -s //a/b:lib
...
a/b/c/1.cpp:13:10: fatal error: 1.hpp: No such file or directory
13 | #include "1.hpp"
|
Interestingly enough, it prints me gcc command that it invokes during build and if I run this command, compiler is able to find 1.hpp and 1.cpp compiles.
How to make bazel "see" this includes? Do I really need to additionally specify copts for every target in addition to global -I flags?
Bazel use sandboxing: for each action (compile a C++ file, link a library) the specific build directory is prepared. That directory contains only files (using symlinks and other Linux sorcery), which are explicitly defined as dependency/source/header for given target.
That trick with --copt=-Ia/b/c is a bad idea, because that option will work only for targets, which depend on //a/b:lib.
Use includes or strip_include_prefix attribute instead:
cc_library(
name = "lib",
srcs = ["c/1.cpp"],
hdrs = ["c/1.hpp"],
strip_include_prefix = "c",
visibility = ["//visibility:public"]
)
and add the lib as a dependency of every target, which need to access these headers:
cc_binary(
name = "some bin",
srcs = ["foo.cpp"],
deps = ["//a/b:lib"],
)

How can I control what symbols are exported from a shared library in Bazel?

I'm learning Bazel, because I have to use it at work. I have a simple build rule that creates a library from a single file and I would like control what is exported by the linker by using a linker version file. (I'm on Linux)
So I tried:
cc_library (
name ="thelib",
srcs = ["lib.cpp"],
linkopts = ["-Wl,--version-script,lib.ver"]
)
And it tells me "No such file or directory".
What have I tried:
I tried a path relative to the directory I issue the bazel build command with no avail.
cc_library()'s documentation says "linkopts" support make variable substitution so I listed the make variables with bazel info --show_make_env it showed me a variable called workspace
so I then tried $(workspace)/lib/lib.ver but then it says $(workspace) not defined so Bazel is a liar.
The only thing that works is spelling the absolute path to the linker script but I don't want to push that.
cc_library() has a win_def_file option but guess what, that's Windows only.
A self-closed github issue suggests that I should pass the filename as a separate argument, it doesn't work either.
Using -fvisiblity=hidden and export using __attribute__ to export is not an option because the standard C++ library overrides it and forces exporting of the symbols you don't want to appear on the interface (the library is used using extern "C" interface only I don't want any other garbage appear on it).
There doesn't seem to be an option in Bazel to specify the symbols to export natively.
At this point I completely ran out of ideas. Any help is appreciated.
First of all, shared libraries are generally declared with cc_binary in conjunction with its linkshared attribute rather than cc_library. This is counterintuitive but reflects the intention that cc_binary creates a transitive link while cc_library declares an intermediate library. (More adventurous folks may try out cc_shared_library
Second of all, it's possible to use version scripts (and other linker scripts) by using them in linkopts and declaring them as a dependency in deps.
So, all together:
cc_binary(
name = 'mylib.so',
linkshared = True,
srcs = ['mylib.cc'],
linkopts = ['-Wl,-version-script=$(location version-script.lds)'],
deps = [
'version-script.lds',
]
)

Bazel create C++ shared library with soname

I would like to create a shared c++ library with Bazel using a soname.
With cmake I could set properties like:
set_target_properties(my-library
PROPERTIES
SOVERSION 3
VERSION 3.2.0
)
which would then generate
libmy-library.so -> libmy-library.so.3
libmy-library.so.3 -> libmy-library.so.3.2.0
libmy-library.so.3.2.0
However in bazel documentation I cannot find anything that would allow me to do so easily. I know that I could define the soname and version directly and pass some linkopts in the build file:
cc_binary(
name = "libmy-library.so.3.2.0",
srcs = ["my-library.cpp", "my-library.h"],
linkshared = 1,
linkopts = ["-Wl,-soname,libmy-library.so.3"],
)
which does produce libmy-library.so.3.2.0 with the correct soname, but not the .so file so it would require a whole lot of hacks around to:
create libmy-library.so.3 symlink
create libmy-library.so symlink
create some import rules such that I can build binaries that link with this library.
This does not feel like the right way. What would be the right way to solve such problem?

How incremental is cc_library in bazel

In bazel documentation (https://docs.bazel.build/versions/master/cpp-use-cases.html) there's an example like this:
cc_library(
name = "build-all-the-files",
srcs = glob(["*.cc"])
hdrs = glob(["*.h"]),
)
How incremental it is? I.e. if I change only one of the *.cc files, will it rebuild the whole target or only what's required?
It will just recompile the modified file. Bazel will then link the library if the object file changes (so if you just change a comment, it may skip the link step).
You still have doubts?
Add the flag -s when you build and you will see what Bazel actually runs.