Features
Explicit Dependency Management
What is Explicit Dependency Management?
In Bazel, Explicit Dependency Management means that you must clearly and explicitly list all the dependencies that your build targets need. Unlike some other build systems where dependencies might be inferred automatically, Bazel requires you to specify each dependency directly. The dependency graph in Bazel must always be a directed acyclic graph which means no cycles are allowed.
Basic Idea
Clear Declaration: You must list every file, library, or target your build depends on in your build configuration files. This ensures that Bazel knows exactly what each target needs to build correctly.
No Implicit Dependencies: There is no automatic assumption about what dependencies a target might need based on file locations or other heuristics. Everything must be explicitly stated.
Example Scenario
Letβs say youβre working on a project with a library and an application that depends on that library. Hereβs how youβd manage dependencies in Bazel:
Project Structure:
lessCopy codemy_project/ βββ //app β βββ BUILD.bazel β βββ main.py βββ //lib βββ BUILD.bazel βββ utils.pyTargets and Dependencies:
//lib:utils- A target that builds a library with utility functions.//app:main- A target that builds an application and depends on the utility functions.
Setting Up Explicit Dependencies:
//lib/BUILD.bazelpy_library( name = "utils", srcs = ["utils.py"], )//app/BUILD.bazelpy_binary( name = "main", srcs = ["main.py"], deps = ["//lib:utils"], # Explicitly declare the dependency on //lib:utils )
Explanation
Explicit Declaration:
In the
//lib/BUILD.bazelfile, thepy_librarytarget//lib:utilsis defined with its source files. This target represents the library with utility functions.In the
//app/BUILD.bazelfile, thepy_binarytarget//app:mainis defined as a Python binary. Thedepsattribute explicitly lists//lib:utilsas a dependency. This means that//app:mainrequires//lib:utilsto build.
No Implicit Dependencies:
Bazel doesnβt guess or infer that
//app:mainmight need//lib:utilsbased on file paths or other heuristics. You must explicitly state this dependency in thedepsattribute.
Benefits
Predictability: By explicitly declaring all dependencies, you ensure that your build is predictable and reproducible. You know exactly what each target depends on.
Clarity: It makes the build configuration clear and understandable. Anyone looking at the build files can see all the dependencies listed without guessing.
Error Prevention: It reduces the risk of build errors due to missing dependencies. Since everything is declared explicitly, Bazel will catch any missing dependencies and prompt you to fix them.
Comparison to Implicit Dependencies
Implicit Dependencies: In some build systems, dependencies might be inferred based on file locations or naming conventions. This can lead to unexpected issues if the system makes incorrect assumptions.
Explicit Dependencies (Bazel): Bazelβs requirement for explicit declarations avoids such issues. You specify exactly what each target needs, which makes the build process more reliable.
Summary
Explicit Dependency Management in Bazel means you must clearly list every dependency your build targets require. This approach ensures that your build process is predictable, clear, and free from implicit assumptions about what dependencies are needed. By specifying dependencies directly in your build configuration files, you avoid potential issues and make your project easier to manage.
Advanced Visibility Features
What is Visibility in Bazel?
In Bazel, visibility is a feature that allows you to control which parts of your code can access or depend on specific build targets. This helps you manage and restrict how different parts of your project interact with each other, improving modularity and reducing the risk of unintended dependencies.
Basic Idea
Visibility Control: You can limit which packages or targets are allowed to depend on a particular target. This way, you can keep certain parts of your codebase hidden from others and only expose what's necessary.
Example Scenario
Imagine you have a project with multiple modules:
Project Structure:
my_project/
βββ //frontend
β βββ BUILD.bazel
β βββ main.py
βββ //backend
β βββ BUILD.bazel
β βββ service.py
βββ //shared
βββ BUILD.bazel
βββ utils.pyTargets and Visibility:
//frontend:main- A target that builds the frontend module.//backend:service- A target that builds the backend module.//shared:utils- A target that builds some shared utility functions.
Setting Up Visibility:
You want to allow only the
frontendmodule to use the utilities fromshared, but you donβt want thebackendmodule to have access to these utilities.
Hereβs how you can set it up in Bazel:
//shared/BUILD.bazel
pythonCopy codepy_library(
name = "utils",
srcs = ["utils.py"],
visibility = ["//frontend:__pkg__"], # Only the frontend module can use this target
)//frontend/BUILD.bazel
pythonCopy codepy_binary(
name = "main",
srcs = ["main.py"],
deps = ["//shared:utils"], # Can depend on utils
)//backend/BUILD.bazel
pythonCopy codepy_binary(
name = "service",
srcs = ["service.py"],
# No dependency on //shared:utils, as it's not listed here
)Explanation
Visibility Declaration:
In the
//shared/BUILD.bazelfile, thevisibilityattribute for//shared:utilsis set to["//frontend:__pkg__"]. This means that only targets in thefrontendpackage can see and depend on the//shared:utilstarget.
Controlled Access:
The
frontendmodule can use theutilslibrary because it is explicitly allowed by the visibility setting.The
backendmodule cannot access theutilslibrary because itβs not listed in the visibility setting. This prevents unintended dependencies and keeps thebackendmodule isolated from thesharedutilities.
Benefits
Modularity: By controlling visibility, you can better organize your project and enforce modular design. Each part of the project only has access to the dependencies it needs.
Maintainability: It reduces the risk of changes in one part of the project affecting others unintentionally, making the project easier to maintain and refactor.
Summary
Bazelβs visibility feature lets you control which parts of your project can access specific build targets. By using visibility, you can limit dependencies and keep different parts of your codebase modular and isolated, similar to how you might use package visibility in Java or namespaces in C++.
TODO:
Remote Build Execution and Caching
Build Dependency Analysis
Fast, Correct Builds (and Tests)
Last updated
Was this helpful?