BazelDeps
Important
This feature is still under development, while it is recommended and usable and we will try not to break them in future releases, some breaking changes might still happen if necessary to prepare for the Conan 2.0 release.
Available since: 1.37.0
BazelDeps
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()
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 Repository and target names.
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
.
Since Conan 1.62.0, 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):
# DEPRECATED: Default generators folder will be "conan" in Conan 2.x
self.folders.generators = "conan"
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()
build_context_activated
Available since: 1.62.0
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):
# DEPRECATED: Default generators folder will be "conan" in Conan 2.x
self.folders.generators = "conan"
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
Available since: 1.62.0
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")
Repository and target names
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.
For instance, if openssl/3.1.4
recipe would have has these bazel_target_name
and bazel_repository_name
properties already declared:
from conan import ConanFile
class OpenSSLConan(ConanFile):
name = "openssl"
# any code here
def package_info(self):
self.cpp_info.set_property("bazel_target_name", "local_openssl")
self.cpp_info.set_property("bazel_repository_name", "OpenSSL")
self.cpp_info.components["crypto"].set_property("bazel_target_name", "libcrypto")
self.cpp_info.components["ssl"].set_property("bazel_target_name", "libssl")
Run conan install openssl/3.1.4@ -g BazelDeps and check the *.pc
files created:
$ conan install . -pr:b default
.
├── conan
│ ├── BUILD.bazel
│ ├── OpenSSL
│ │ └── BUILD.bazel
│ └── dependencies.bzl
└── conanfile.py
The labels to use in your personal BUILD file would be:
@OpenSSL//:local_openssl
@OpenSSL//:libssl
@OpenSSL//:libcrypto
@OpenSSL//:local_openssl_binaries
An example of a BUILD file consuming one of these targets could be something like this:
load("@rules_cc//cc:defs.bzl", "cc_binary")
cc_binary(
name = "example",
srcs = ["example.cpp"],
deps = [
"@OpenSSL//:local_openssl",
],
)