diff --git a/examples/tools/google/bazel.rst b/examples/tools/google/bazel.rst index d21bfa514fb0..551fc8aba07f 100644 --- a/examples/tools/google/bazel.rst +++ b/examples/tools/google/bazel.rst @@ -8,3 +8,4 @@ Bazel :maxdepth: 2 bazeltoolchain/build_simple_bazel_project + bazeltoolchain/build_simple_bazel_7x_project diff --git a/examples/tools/google/bazeltoolchain/build_simple_bazel_7x_project.rst b/examples/tools/google/bazeltoolchain/build_simple_bazel_7x_project.rst new file mode 100644 index 000000000000..373d3f1e3732 --- /dev/null +++ b/examples/tools/google/bazeltoolchain/build_simple_bazel_7x_project.rst @@ -0,0 +1,142 @@ +.. _examples_tools_bazel_7x_toolchain_build_simple_bazel_project: + +Build a simple Bazel 7.x project using Conan +============================================ + +.. warning:: + + This example is Bazel >= 7.1 compatible. + +In this example, we are going to create a Hello World program +that uses one of the most popular C++ libraries: `fmt `_. + +.. note:: + + This example is based on the :ref:`Build a simple CMake project using Conan` + tutorial. So we highly recommend reading it before trying out this one. + + +We'll use Bazel as the build system and helper tool in this case, so you should get it installed +before going forward with this example. See `how to install Bazel `_. + +Please, first clone the sources to recreate this project. You can find them in the +`examples2 repository `_ in GitHub: + +.. code-block:: bash + + $ git clone https://github.com/conan-io/examples2.git + $ cd examples2/examples/tools/google/bazeltoolchain/7_x/string_formatter + + +We start from a very simple C++ language project with this structure: + +.. code-block:: text + + . + ├── MODULE.bazel + ├── conanfile.txt + └── main + ├── BUILD + └── demo.cpp + +This project contains a *MODULE.bazel* file loading the Conan dependencies (in this case only ``fmt``) +and a *main/BUILD* file which defines the *demo* bazel target and it's in charge of using ``fmt`` to build a +simple Hello World program. + +Let's have a look at each file's content: + +.. code-block:: cpp + :caption: **main/demo.cpp** + + #include + #include + + int main() { + fmt::print("{} - The C++ Package Manager!\n", "Conan"); + return EXIT_SUCCESS; + } + +.. code-block:: python + :caption: **MODULE.bazel** + + load_conan_dependencies = use_extension("//conan:conan_deps_module_extension.bzl", "conan_extension") + use_repo(load_conan_dependencies, "fmt") + + +.. code-block:: python + :caption: **main/BUILD** + + cc_binary( + name = "demo", + srcs = ["demo.cpp"], + deps = [ + "@fmt//:fmt" + ], + ) + + +.. code-block:: ini + :caption: **conanfile.txt** + + [requires] + fmt/10.1.1 + + [generators] + BazelDeps + BazelToolchain + + [layout] + bazel_layout + + +Conan uses the :ref:`conan_tools_google_bazeltoolchain` to generate a ``conan_bzl.rc`` file which defines the +``conan-config`` bazel-build configuration. This file and the configuration are passed as parameters to the +``bazel build`` command. Apart from that, Conan uses the :ref:`conan_tools_google_bazeldeps` generator +to create all the bazel files (*[DEP]/BUILD.bazel*, *conan_deps_module_extension.bzl* and +*conan_deps_repo_rules.bzl*) which define the rule and all the dependencies to create/load them as Bazel repositories. +The *MODULE.bazel* above is ready to load the *conan_deps_module_extension.bzl* file which will tell the +*main/BUILD* all the information about the ``@fmt//:fmt`` bazel target. + +As the first step, we should install all the dependencies listed in the ``conanfile.txt``. +The command :ref:`conan install` does not only install the ``fmt`` package, +it also builds it from sources in case your profile does not match with a pre-built binary in your remotes. +Furthermore, it will save all the files created by the generators listed in the ``conanfile.txt`` +in a folder named *conan/* (default folder defined by the ``bazel_layout``). + +.. code-block:: bash + + $ conan install . --build=missing + # ... + ======== Finalizing install (deploy, generators) ======== + conanfile.txt: Writing generators to /Users/user/develop/examples2/examples/tools/google/bazeltoolchain/7_x/string_formatter/conan + conanfile.txt: Generator 'BazelDeps' calling 'generate()' + conanfile.txt: Generator 'BazelToolchain' calling 'generate()' + conanfile.txt: Generating aggregated env files + conanfile.txt: Generated aggregated env files: ['conanbuild.sh', 'conanrun.sh'] + Install finished successfully + +Now we are ready to build and run our application: + +.. code-block:: bash + + $ bazel --bazelrc=./conan/conan_bzl.rc build --config=conan-config //main:demo + Computing main repo mapping: + Loading: + Loading: 0 packages loaded + Analyzing: target //main:demo (1 packages loaded, 0 targets configured) + Analyzing: target //main:demo (1 packages loaded, 0 targets configured) + [0 / 1] [Prepa] BazelWorkspaceStatusAction stable-status.txt + INFO: Analyzed target //main:demo (69 packages loaded, 369 targets configured). + [5 / 7] Compiling main/demo.cpp; 0s darwin-sandbox + INFO: Found 1 target... + Target //main:demo up-to-date: + bazel-bin/main/demo + INFO: Elapsed time: 2.955s, Critical Path: 1.70s + INFO: 7 processes: 5 internal, 2 darwin-sandbox. + INFO: Build completed successfully, 7 total actions + + +.. code-block:: bash + + $ ./bazel-bin/main/demo + Conan - The C++ Package Manager! diff --git a/examples/tools/google/bazeltoolchain/build_simple_bazel_project.rst b/examples/tools/google/bazeltoolchain/build_simple_bazel_project.rst index f658e5f2e85f..0fc63db7baca 100644 --- a/examples/tools/google/bazeltoolchain/build_simple_bazel_project.rst +++ b/examples/tools/google/bazeltoolchain/build_simple_bazel_project.rst @@ -3,6 +3,10 @@ Build a simple Bazel project using Conan ======================================== +.. warning:: + + This example is Bazel 6.x compatible. + In this example, we are going to create a Hello World program that uses one of the most popular C++ libraries: `fmt `_. @@ -21,7 +25,7 @@ Please, first clone the sources to recreate this project. You can find them in t .. code-block:: bash $ git clone https://github.com/conan-io/examples2.git - $ cd examples2/examples/tools/google/bazeltoolchain/string_formatter + $ cd examples2/examples/tools/google/bazeltoolchain/6_x/string_formatter We start from a very simple C++ language project with this structure: @@ -62,8 +66,6 @@ Let's have a look at each file's content: .. code-block:: python :caption: **main/BUILD** - load("@rules_cc//cc:defs.bzl", "cc_binary") - cc_binary( name = "demo", srcs = ["demo.cpp"], @@ -105,7 +107,7 @@ in a folder named *conan/* (default folder defined by the ``bazel_layout``). $ conan install . --build=missing # ... ======== Finalizing install (deploy, generators) ======== - conanfile.txt: Writing generators to /Users/franchuti/develop/examples2/examples/tools/google/bazeltoolchain/string_formatter/conan + conanfile.txt: Writing generators to /Users/user/develop/examples2/examples/tools/google/bazeltoolchain/6_x/string_formatter/conan conanfile.txt: Generator 'BazelDeps' calling 'generate()' conanfile.txt: Generator 'BazelToolchain' calling 'generate()' conanfile.txt: Generating aggregated env files diff --git a/integrations/bazel.rst b/integrations/bazel.rst index ac606d24551e..bffe078bd676 100644 --- a/integrations/bazel.rst +++ b/integrations/bazel.rst @@ -21,6 +21,7 @@ imported from ``conan.tools.google``. The most relevant tools are: - Reference for :ref:`conan_tools_google_bazeltoolchain`. - Reference for :ref:`conan_tools_google_bazel`. - :ref:`examples_tools_bazel_toolchain_build_simple_bazel_project` + - :ref:`examples_tools_bazel_7x_toolchain_build_simple_bazel_project` .. |bazel_logo| image:: ../images/integrations/conan-bazel-logo.png diff --git a/reference/tools/google/bazel.rst b/reference/tools/google/bazel.rst index 6cdf6aff7714..11b98e29528a 100644 --- a/reference/tools/google/bazel.rst +++ b/reference/tools/google/bazel.rst @@ -54,3 +54,4 @@ conf .. seealso:: - :ref:`examples_tools_bazel_toolchain_build_simple_bazel_project` + - :ref:`examples_tools_bazel_7x_toolchain_build_simple_bazel_project` diff --git a/reference/tools/google/bazeldeps.rst b/reference/tools/google/bazeldeps.rst index 9c9e2c197e03..0e98e420bbff 100644 --- a/reference/tools/google/bazeldeps.rst +++ b/reference/tools/google/bazeldeps.rst @@ -7,7 +7,9 @@ BazelDeps The ``BazelDeps`` is the dependencies generator for Bazel. Generates a */BUILD.bazel* file per dependency, where the */* 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. +that, it also generates Bazel 6.x compatible file like *dependencies.bzl*, and other Bazel >= 7.1 compatible ones +like *conan_deps_module_extension.bzl* and *conan_deps_repo_rules.bzl*. All of them contain the logic to load +all your Conan dependencies through your *WORKSPACE* | *MODULE.bazel*. The ``BazelDeps`` generator can be used by name in conanfiles: @@ -17,6 +19,7 @@ The ``BazelDeps`` generator can be used by name in conanfiles: class Pkg(ConanFile): generators = "BazelDeps" + .. code-block:: text :caption: conanfile.txt @@ -59,12 +62,20 @@ Every :command:`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 :ref:`conan_tools_google_bazeldeps_customization`. +* *dependencies.bzl*: (Bazel 6.x compatible) this file tells your Bazel *WORKSPACE* how to load the dependencies. +* *conan_deps_module_extension.bzl*: (since `Conan 2.4.0 `_)(Bazel >= 7.1 compatible) + This file is used to load each dependency as repository. +* *conan_deps_repo_rules.bzl*: (since `Conan 2.4.0 `_)(Bazel >= 7.1 compatible) + The rule provided by this file is used to create a repository. + It is not intended to be used by consumers but by *conan_deps_module_extension.bzl*. Let's check the content of the files created: +**Bazel 6.x compatible** + + .. code-block:: python :caption: dependencies.bzl @@ -80,7 +91,84 @@ Let's check the content of the files created: 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: +**Bazel >= 7.1 compatible** + +.. code-block:: python + :caption: conan_deps_repo_rules.bzl + + # This bazel repository rule is used to load Conan dependencies into the Bazel workspace. + # It's used by a generated module file that provides information about the conan packages. + # Each conan package is loaded into a bazel repository rule, with having the name of the + # package. The whole method is based on symlinks to not copy the whole package into the + # Bazel workspace, which is expensive. + def _conan_dependency_repo(rctx): + package_path = rctx.workspace_root.get_child(rctx.attr.package_path) + + child_packages = package_path.readdir() + for child in child_packages: + rctx.symlink(child, child.basename) + + rctx.symlink(rctx.attr.build_file_path, "BUILD.bazel") + + conan_dependency_repo = repository_rule( + implementation = _conan_dependency_repo, + attrs = { + "package_path": attr.string( + mandatory = True, + doc = "The path to the Conan package in conan cache.", + ), + "build_file_path": attr.string( + mandatory = True, + doc = "The path to the BUILD file.", + ), + }, + ) + + + +.. code-block:: python + :caption: conan_deps_module_extension.bzl + + + # This module provides a repo for each requires-dependency in your conanfile. + # It's generated by the BazelDeps, and should be used in your Module.bazel file. + load(":conan_deps_repo_rules.bzl", "conan_dependency_repo") + + def _load_dependenies_impl(mctx): + conan_dependency_repo( + name = "zlib", + package_path = "/path/to/conan/package/folder/", + build_file_path = "/your/current/working/directory/zlib/BUILD.bazel", + ) + + return mctx.extension_metadata( + # It will only warn you if any direct + # dependency is not imported by the 'use_repo' or even it is imported + # but not created. Notice that root_module_direct_dev_deps can not be None as we + # are giving 'all' value to root_module_direct_deps. + # Fix the 'use_repo' calls by running 'bazel mod tidy' + root_module_direct_deps = 'all', + root_module_direct_dev_deps = [], + + # Prevent writing function content to lockfiles: + # - https://bazel.build/rules/lib/builtins/module_ctx#extension_metadata + # Important for remote build. Actually it's not reproducible, as local paths will + # be different on different machines. But we assume that conan works correctly here. + # IMPORTANT: Not compatible with bazel < 7.1 + reproducible = True, + ) + + conan_extension = module_extension( + implementation = _load_dependenies_impl, + os_dependent = True, + arch_dependent = True, + ) + + +Given the examples above, and imagining that your *WORKSPACE* | *MODULE.bazel* is at the same directory, +you would have to add these lines in there: + +**Bazel 6.x compatible** .. code-block:: python :caption: WORKSPACE @@ -89,10 +177,20 @@ Given the example above, and imagining that your WORKSPACE is at the same direct load_conan_dependencies() +**Bazel >= 7.1 compatible** + .. code-block:: python - :caption: zlib/BUILD.bazel + :caption: MODULE.bazel + + load_conan_dependencies = use_extension("//:conan_deps_module_extension.bzl", "conan_extension") + # use_repo(load_conan_dependencies, "dep1", "dep2", ..., "depN") + use_repo(load_conan_dependencies, "zlib") + + +As you can observe, the *zlib/BUILD.bazel* defines these global targets: - load("@rules_cc//cc:defs.bzl", "cc_import", "cc_library") +.. code-block:: python + :caption: zlib/BUILD.bazel # Components precompiled libs # Root package precompiled libs @@ -126,7 +224,6 @@ Given the example above, and imagining that your WORKSPACE is at the same direct 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``. @@ -160,12 +257,14 @@ Running again the :command:`conan install` command, we now get this structure: ├── conan │ ├── BUILD.bazel │ ├── dependencies.bzl + │ ├── conan_deps_module_extension.bzl + │ ├── conan_deps_repo_rules.bzl │ └── zlib │ └── BUILD.bazel └── conanfile.py -Now your Conan-bazel files were generated in the *conan/* folder, so your WORKSPACE will look like: +Now your Conan-bazel files were generated in the *conan/* folder, your WORKSPACE will look like: .. code-block:: python :caption: WORKSPACE @@ -173,6 +272,16 @@ Now your Conan-bazel files were generated in the *conan/* folder, so your WORKSP load("@//conan:dependencies.bzl", "load_conan_dependencies") load_conan_dependencies() + +Or your MODULE.bazel: + +.. code-block:: python + :caption: MODULE.bazel + + load_conan_dependencies = use_extension("//conan:conan_deps_module_extension.bzl", "conan_extension") + use_repo(load_conan_dependencies, "zlib") + + .. _conan_tools_google_bazeldeps_customization: Customization @@ -241,6 +350,8 @@ Running the :command:`conan install` command, the structure created is as follow │ ├── BUILD.bazel │ ├── build-my_tool │ │ └── BUILD.bazel + │ ├── conan_deps_module_extension.bzl + │ ├── conan_deps_repo_rules.bzl │ └── dependencies.bzl └── conanfile.py @@ -271,3 +382,4 @@ Example: .. seealso:: - :ref:`examples_tools_bazel_toolchain_build_simple_bazel_project` + - :ref:`examples_tools_bazel_7x_toolchain_build_simple_bazel_project` diff --git a/reference/tools/google/bazeltoolchain.rst b/reference/tools/google/bazeltoolchain.rst index 26b14155176d..5e51166dd176 100644 --- a/reference/tools/google/bazeltoolchain.rst +++ b/reference/tools/google/bazeltoolchain.rst @@ -81,3 +81,4 @@ conf .. seealso:: - :ref:`examples_tools_bazel_toolchain_build_simple_bazel_project` + - :ref:`examples_tools_bazel_7x_toolchain_build_simple_bazel_project` diff --git a/tutorial/consuming_packages/build_simple_cmake_project.rst b/tutorial/consuming_packages/build_simple_cmake_project.rst index b4c87bc41f20..d5644f1ba64b 100644 --- a/tutorial/consuming_packages/build_simple_cmake_project.rst +++ b/tutorial/consuming_packages/build_simple_cmake_project.rst @@ -271,3 +271,4 @@ Now we are ready to build and run our **compressor** app: - :ref:`Getting started with Autotools` - :ref:`Getting started with Meson` - :ref:`Getting started with Bazel` + - :ref:`Getting started with Bazel 7.x`