Manage code dependencies
The Intrinsic SDK uses Bazel, an open-source build and test tool similar to cmake, Maven, and Gradle, as its build system. The Intrinsic Visual Studio Code plugin manages Bazel complexities automatically, allowing developers to focus on code without needing deep knowledge of Bazel. However, there are some situations, such as managing code dependencies, where knowing about Bazel is helpful.
Bazel's handling of software dependencies might be different than you are used to. This page describes how to manage software dependencies when writing your own skills.
Share code within your Bazel workspace
Say you are creating two skills. Both skills inspect parts, and both need to check if a measurement is within tolerance. Don't write the same code twice; reuse it!
Create a reusable library
Create a new bazel package for your inspection code.
- Create a folder next to your
MODULE.bazelfile calledinspection. - Create a file
inspection/BUILD.
The next steps depend on your chosen programming language.
- Python
- C++
-
Create a file
inspection/measurements.pyYour bazel workspace has two new files:
MODULE.bazel
inspection/BUILD
inspection/measurements.py
... other files ... -
Put the code you want to reuse into
measurements.py.def within_tolerance(measured, expected, allowed_difference):
actual_difference = measured - expected
return abs(actual_difference) <= abs(allowed_difference) -
Put the following into
BUILDto create a bazel target for your Python library using apy_libraryrule.load("@rules_python//python:defs.bzl", "py_library")
py_library(
name = "measurements",
srcs = ["measurements.py"],
visibility = ["//visibility:public"],
)
You now have a reusable Python library.
-
Create a file
inspection/measurements.h -
Create a file
inspection/measurements.ccYour bazel workspace has three new files:
MODULE.bazel
inspection/BUILD
inspection/measurements.h
inspection/measurements.cc
... other files ... -
Put a function declaration for the code you want to reuse into
measurements.h.#pragma once
float WithinTolerance(measured, expected, allowed_difference); -
Put a function definition for the code you want to reuse into
measurements.cc.#include "inspection/measurements.h"
#include <cmath>
float WithinTolerance(measured, expected, allowed_difference) {
float actual_difference = measured - expected;
return std::fabs(actual_difference) <= std::fabs(allowed_difference);
} -
Put the following into
BUILDto create a bazel target for your Python library using acc_libraryrule.cc_library(
name = "measurements",
hdrs = ["measurements.h"],
srcs = ["measurements.cc"],
visibility = ["//visibility:public"],
)
You now have a reusable C++ library.
Use a reusable library
In order to reuse your library, you need to know its bazel label. Your library has the bazel label:
//inspection:measurements
Here's what each part means:
//is the root of your bazel workspaceinspectionis the path to your bazel package:measurementsis a target namedmeasurementsin that bazel package
How you use the bazel label depends on your chosen programming language.
- Python
- C++
Locate the py_library target for your skill in its BUILD file.
It should be above py_skill bazel target.
Add the bazel label of your inspection library to the deps attribute of your skill's py_library target.
py_library(
name = "inspect_brackets_skill_py",
srcs = ["inspect_brackets_skill.py"],
deps = [
"//inspection:measurements",
# ... other dependencies omitted ...
],
)
Import the within_tolerance function in your skill's python file.
from inspection.measurements import within_tolerance
Locate the cc_library target for your skill in its BUILD file.
It should be above cc_skill bazel target.
Add the bazel label of your inspection library to the deps attribute of your skill's cc_library target.
cc_library(
name = "inspect_brackets_skill_cc",
srcs = ["inspect_brackets_skill.cc"],
hdrs = ["inspect_brackets_skill.h"],
deps = [
"//inspection:measurements",
# ... other dependencies omitted ...
],
)
Include the measurements.h header in your skill's C++ file.
#include "inspection/measurements.h"
Add an external dependency
Bazel manages external dependencies with bazel repository rules. They tell bazel how to get external dependencies.
Get Python packages from the Python Package Index
The Python Package Index (PyPI) hosts many python packages.
Use the bazel repository rules provided by rules_python to download python packages from PyPI using the Python package installer pip.
Create bazel repository rules for NumPy and OpenCV by following these instructions:
-
Create a file
requirements.innext to yourMODULE.bazelfile. -
Put the following content (the Python package names for NumPy and OpenCV) into
requirements.in:numpy
opencv-python-headless -
Create an empty file
requirements_lock.txtnext torequirements.in. -
Create a file
BUILDnext torequirements.in. -
Add the following content to
BUILD:load("@rules_python//python:pip.bzl", "compile_pip_requirements")
compile_pip_requirements(
name = "requirements",
src = ":requirements.in",
requirements_txt = ":requirements_lock.txt",
) -
Ensure a dependency on
rules_pythonexists inMODULE.bazel. If you are using theMODULE.bazelgenerated byinctl bazel init, this rule will already be includedbazel_dep(name = "rules_python", version = "0.31.0")
python = use_extension("@rules_python//python/extensions:python.bzl", "python") -
Run the following command to update
requirements_lock.txt:bazel run //:requirements.update -
Create a repo rule In your
MODULE.bazelfile, add a dependency torules_pythonand load thepipextension if not already present.## Toolchain is declared once per MODULE
python.toolchain(
is_default = True,
python_version = "3.11",
)
pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
# Each skill or service can declare their own set of requirements.
# In this example, use a single top-level requirements file
pip.parse(
hub_name = "pypi_deps",
python_version = "3.11",
requirements_lock = "//:requirements_lock.txt",
)
use_repo(pip, "pypi_deps")Note that the
hub_namespecified in theMODULE.bazelfile will dictate how dependencies appear in theBUILD.bazelfiles. PyPI-derived rules will appear in the fomat@<hub_name>//<pkg_name>:pkg. In this casenumpywill appear as@pypi_deps//numpy:pkg.
Your bazel workspace now has bazel repository rules that tell bazel how to get NumPy and OpenCV from PyPI.
Make your skill's py_library target depend on them with the following instructions:
-
Locate the
BUILDfile for your skill. For example:my_skill/BUILD -
Add dependencies on NumPy and OpenCV to the
depsattribute of your skill'spy_librarybazel target.py_library(
name = "my_skill_py",
srcs = ["my_skill.py"],
deps = [
"@pypi_deps//numpy:pkg",
"@pypi_deps//opencv_python_headless:pkg",
# ... other dependencies omitted ...
],
) -
Import NumPy and OpenCV in your skill's Python file.
import numpy as np
import cv2