BazelDeps¶
Warning
This feature is experimental and subject to breaking changes. See the Conan stability section for more information.
The BazelDeps
is the dependencies generator for Bazel. Generates a <REPOSITORY>/BUILD.bazel file per dependency,
where the <REPOSITORY>/ folder is the Conan recipe reference name by default, e.g., mypkg/BUILD.bazel. Apart from
that, it also generates a dependencies.bzl file which contains a Bazel function to load all your Conan dependencies.
The BazelDeps
generator can be used by name in conanfiles:
class Pkg(ConanFile):
generators = "BazelDeps"
[generators]
BazelDeps
And it can also be fully instantiated in the conanfile generate()
method:
from conan import ConanFile
from conan.tools.google import BazelDeps
class App(ConanFile):
settings = "os", "arch", "compiler", "build_type"
requires = "zlib/1.2.11"
def generate(self):
bz = BazelDeps(self)
bz.generate()
Generated files¶
When the BazelDeps
generator is used, every invocation of conan install
will
generate several bazel files. For the conanfile.py
above, for example:
$ conan install .
.
├── BUILD.bazel
├── conanfile.py
├── dependencies.bzl
└── zlib
└── BUILD.bazel
Every conan install generates these files:
BUILD.bazel: An empty file aimed to be alongside the dependencies.bzl one. More information here.
dependencies.bzl: this file tells your Bazel WORKSPACE how to load the dependencies.
zlib/BUILD.bazel: contains all the targets that you can load from any of your BUILD files. More information in Customization.
Let’s check the content of the files created:
# This Bazel module should be loaded by your WORKSPACE file.
# Add these lines to your WORKSPACE one (assuming that you're using the "bazel_layout"):
# load("@//conan:dependencies.bzl", "load_conan_dependencies")
# load_conan_dependencies()
def load_conan_dependencies():
native.new_local_repository(
name="zlib",
path="/path/to/conan/package/folder/",
build_file="/your/current/working/directory/zlib/BUILD.bazel",
)
Given the example above, and imagining that your WORKSPACE is at the same directory, you would have to add these lines in there:
load("@//:dependencies.bzl", "load_conan_dependencies")
load_conan_dependencies()
load("@rules_cc//cc:defs.bzl", "cc_import", "cc_library")
# Components precompiled libs
# Root package precompiled libs
cc_import(
name = "z_precompiled",
static_library = "lib/libz.a",
)
# Components libraries declaration
# Package library declaration
cc_library(
name = "zlib",
hdrs = glob([
"include/**",
]),
includes = [
"include",
],
visibility = ["//visibility:public"],
deps = [
":z_precompiled",
],
)
# Filegroup library declaration
filegroup(
name = "zlib_binaries",
srcs = glob([
"bin/**",
]),
visibility = ["//visibility:public"],
)
As you can observe, the zlib/BUILD.bazel defines these global targets:
zlib
: bazel library target. The label used to depend on it would be@zlib//:zlib
.zlib_binaries
: bazel filegroup target. The label used to depend on it would be@zlib//:zlib_binaries
.
You can put all the files generated by BazelDeps
into another folder using the bazel_layout
:
from conan import ConanFile
from conan.tools.google import BazelDeps, bazel_layout
class App(ConanFile):
settings = "os", "arch", "compiler", "build_type"
requires = "zlib/1.2.11"
def layout(self):
bazel_layout(self)
def generate(self):
bz = BazelDeps(self)
bz.generate()
Running again the conan install command, we now get this structure:
$ conan install .
.
├── conan
│ ├── BUILD.bazel
│ ├── dependencies.bzl
│ └── zlib
│ └── BUILD.bazel
└── conanfile.py
Now your Conan-bazel files were generated in the conan/ folder, so your WORKSPACE will look like:
load("@//conan:dependencies.bzl", "load_conan_dependencies")
load_conan_dependencies()
Customization¶
Naming¶
The <REPOSITORY>/BUILD.bazel
file contains all the targets declared by the dependency. Both the <REPOSITORY>/
folder and the targets
declared in there will be named following these rules by default:
- For packages, it uses the package name as folder/target name, e.g., package
zlib/1.2.11
will have: Folder:
zlib/BUILD.bazel
.Global target:
zlib
.How it can be consumed:
@zlib//:zlib
.
- For packages, it uses the package name as folder/target name, e.g., package
- For components, the package name + hyphen + component name, e.g., package
openssl/3.1.4
will have: Folder:
openssl/BUILD.bazel
.Global target:
openssl
.Components targets:
openssl-ssl
, andopenssl-crypto
.- How it can be consumed:
@openssl//:openssl
(global one which includes all the components)@openssl//:openssl-ssl
(component one)@openssl//:openssl-crypto
(component one)
- For components, the package name + hyphen + component name, e.g., package
You can change that default behavior with the bazel_target_name
and the bazel_repository_name
properties.
See Properties section below.
Reference¶
- class BazelDeps(conanfile)¶
- Parameters:
conanfile –
< ConanFile object >
The current recipe object. Always useself
.
- build_context_activated¶
Activates the build context for the specified Conan package names.
- generate()¶
Generates all the targets <DEP>/BUILD.bazel files and the dependencies.bzl one in the build folder. It’s important to highlight that the dependencies.bzl file should be loaded by your WORKSPACE Bazel file:
load("@//[BUILD_FOLDER]:dependencies.bzl", "load_conan_dependencies") load_conan_dependencies()
build_context_activated¶
When you have a build-requirement, by default, the Bazel files are not generated. But you can activate it using the build_context_activated attribute:
def build_requirements(self):
self.tool_requires("my_tool/0.0.1")
def layout(self):
bazel_layout(self)
def generate(self):
bz = BazelDeps(self)
# generate the build-mytool/BUILD.bazel file for the tool require
bz.build_context_activated = ["my_tool"]
bz.generate()
Running the conan install command, the structure created is as follows:
$ conan install . -pr:b default
.
├── conan
│ ├── BUILD.bazel
│ ├── build-my_tool
│ │ └── BUILD.bazel
│ └── dependencies.bzl
└── conanfile.py
Notice that my_tool Bazel folder is prefixed with build-
which indicates that it’s being used in the build context.
Properties¶
The following properties affect the BazelDeps
generator:
bazel_target_name property will define the name of the target declared in the
<REPOSITORY>/BUILD.bazel
. This property can be defined at both global and componentcpp_info
level.bazel_repository_name property will define the name of the folder where the dependency BUILD.bazel will be allocated. This property can only be defined at global
cpp_info
level.
Example:
def package_info(self):
self.cpp_info.set_property("bazel_target_name", "my_target")
self.cpp_info.set_property("bazel_repository_name", "my_repo")
self.cpp_info.components["mycomponent"].set_property("bazel_target_name", "component_name")