Build from Source#

This page describes how to build Isaac Teleop from source, including core libraries, plugins, and examples. The instructions align with the project’s CMake configuration and the CI workflow (build-ubuntu.yml in the GitHub repository).

Next Steps

Prerequisites#

  • CMake 3.20 or higher

  • C++20 compatible compiler

  • Python 3.11, 3.12, or 3.13 (default 3.11; see ISAAC_TELEOP_PYTHON_VERSION in root CMakeLists.txt)

  • uv for Python dependency management and managed Python

  • Internet connection for downloading dependencies via CMake FetchContent

One time setup#

Install build tools and dependencies, such as CMake, clang-format. See build-ubuntu.yml in the GitHub repository for the list of dependencies. On Ubuntu, install build tools and clang-format:

sudo apt-get update
sudo apt-get install -y build-essential cmake libx11-dev clang-format-14 ccache patchelf

Runtime-only dependencies (needed to actually run teleop, not to build):

# adb — required for OOB teleop (``--setup-oob``) to talk to the headset over USB.
# coturn — required for USB-local mode (``--usb-local``); runs a local TURN server
#          so WebRTC ICE can relay traffic from the headset to the CloudXR backend
#          over the USB cable.
sudo apt-get install -y android-tools-adb coturn

Our build system uses uv for Python version and dependency management. Install uv if not already installed:

curl -LsSf https://astral.sh/uv/install.sh | sh

Note

While the build system uses uv, the final Python packages can be installed via any Python package manager such as pip or conda.

1. Clone the repository#

git clone https://github.com/NVIDIA/IsaacTeleop.git
cd IsaacTeleop

Note

Dependencies (OpenXR SDK, pybind11, yaml-cpp) are automatically downloaded during CMake configuration using FetchContent. No manual dependency installation or git submodule initialization is required.

Pre-download CloudXR SDK (Optional)#

Note

If you are using the default flow, skip this step. The CMakeLists.txt will automatically download the CloudXR SDK by calling the download_cloudxr_runtime_sdk.sh script.

Sometimes NVIDIA might share early access CloudXR SDKs with you. In that case, you may get tarballs such as:

  • CloudXR-<version-for-runtime-sdk>-Linux-<arch>-sdk.tar.gz (CloudXR Runtime SDK)

  • CloudXR-exp-<version-for-runtime-sdk>-Linux-<arch>-sdk.tar.gz (optional experimental runtime). Needed for Jetson Orin support (for example Televiz) until the default runtime covers those platforms.

  • nvidia-cloudxr-<version-for-web-sdk>.tgz (CloudXR Web SDK)

You can place them in the deps/cloudxr/ directory and update the deps/cloudxr/.env file to locally override the default version defined in deps/cloudxr/.env.default, like this:

CXR_RUNTIME_SDK_VERSION=<version-for-runtime-sdk>
CXR_WEB_SDK_VERSION=<version-for-web-sdk>

To package the experimental runtime into the wheel as isaacteleop.cloudxr_exp, configure with -DENABLE_CLOUDXR_EXP_BUNDLE=ON. Select it at runtime with ISAAC_TELEOP_CLOUDXR_EXP. See Dedicated CloudXR Runtime.

2. CMake: Configure and build#

From the project root:

cmake -B build                       # configure
cmake --build build --parallel       # build
cmake --install build                # install

Add any other options as -D flags on the configure line, for example cmake -B build -DCMAKE_BUILD_TYPE=Debug.

Important

The Python version is baked into a build directory’s CMake cache and its build venv, so ISAAC_TELEOP_PYTHON_VERSION cannot be changed on an existing tree — configuring again with a different value fails with an explanatory error. Give each version its own directory:

cmake -B build-py3.12 -DISAAC_TELEOP_PYTHON_VERSION=3.12
cmake --build build-py3.12 --parallel

This will:

  1. Fetch dependencies (OpenXR SDK, yaml-cpp, pybind11, FlatBuffers, MCAP, and optionally Catch2 for tests) via FetchContent in deps/third_party/CMakeLists.txt

  2. Build core C++ libraries (schema, oxr_utils, plugin_manager, oxr, pusherio, deviceio, mcap, etc.) and Python bindings

  3. Build the Python wheel

  4. Build examples (if enabled)

  5. Install to ./install (default prefix set in root CMakeLists.txt)

C++ Formatting Enforcement (Linux)#

On Linux, clang-format is enforced by default; the build fails if formatting changes would be applied. The project uses clang-format-14 for consistent results across distributions (see cmake/ClangFormat.cmake).

To disable enforcement, set ENABLE_CLANG_FORMAT_CHECK to OFF:

cmake -B build -DENABLE_CLANG_FORMAT_CHECK=OFF

Useful targets:

  • clang_format_check — verifies formatting (part of ALL on Linux)

  • clang_format_fix — applies formatting in place

cmake --build build --target clang_format_check
cmake --build build --target clang_format_fix

Other Build options#

The CMake options (defined in root CMakeLists.txt and cmake/SetupPython.cmake):

Common CMake Options#

Option

CMake flag

Default / Notes

Build type

CMAKE_BUILD_TYPE

Release or Debug

Install prefix

CMAKE_INSTALL_PREFIX

./install

Common Isaac Teleop Options#

Option

CMake flag

Default / Notes

Examples

BUILD_EXAMPLES

ON

Python bindings

BUILD_PYTHON_BINDINGS

ON

Python version

ISAAC_TELEOP_PYTHON_VERSION

3.11 (3.11, 3.12, or 3.13)

Testing

BUILD_TESTING

ON; enables CTest and Catch2

Clang-format check

ENABLE_CLANG_FORMAT_CHECK

ON on Linux

Televiz visualization

BUILD_VIZ

Auto: ON when Vulkan, the CUDA Toolkit, and glslangValidator are detected, else OFF. Force with -DBUILD_VIZ=ON / -DBUILD_VIZ=OFF. (Most users don’t need this — pip install isaacteleop already ships the compiled isaacteleop.viz module.)

Plugin Specific Options#

Option

CMake flag

Default / Notes

Plugins master switch

BUILD_PLUGINS

ON

OAK camera plugin

BUILD_PLUGIN_OAK_CAMERA

OFF; requires Hunter/DepthAI when ON

Teleop ROS2 example only

BUILD_EXAMPLE_TELEOP_ROS2

OFF; when ON, only examples/teleop_ros2 (e.g. Docker)

Examples#

Build for a different Python version — each needs its own build directory (3.11, 3.12, 3.13 are supported):

cmake -B build-py3.12 -DISAAC_TELEOP_PYTHON_VERSION=3.12
cmake --build build-py3.12 --parallel

Debug build:

cmake -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build

Build without examples:

cmake -B build -DBUILD_EXAMPLES=OFF
cmake --build build

Build without Python bindings:

cmake -B build -DBUILD_PYTHON_BINDINGS=OFF
cmake --build build

Build with OAK camera plugin (pulls Hunter/DepthAI):

cmake -B build -DBUILD_PLUGIN_OAK_CAMERA=ON
cmake --build build

Build only the teleop_ros2 example (e.g. for Docker, as in build-ubuntu.yml teleop-ros2-docker job):

cmake -B build -DBUILD_EXAMPLES=OFF -DBUILD_EXAMPLE_TELEOP_ROS2=ON
cmake --build build

Clean rebuild (--fresh wipes the CMake cache and reconfigures):

cmake -B build --fresh
cmake --build build

3. Running tests#

When BUILD_TESTING is ON, CTest is enabled at the top level. Run all tests either via the CMake test target or with ctest:

cmake --build build --target test

# Or with ctest (e.g. parallel, output on failure)
ctest --test-dir build --output-on-failure --parallel

The CI uses ctest (see build-ubuntu.yml).

4. Install the isaacteleop pip package#

The wheels are built in the ./install/wheels/ directory. Install the package from the wheels. Using pip, you need to pass the --no-index option to automatically find the right wheel based on the Python version. Note that pip and uv pip has slightly different options.

# Pass --no-index to use only wheels in ./install/wheels/;
# Pass --force-reinstall to replace an existing install.
pip install "isaacteleop[retargeters,cloudxr,ui]" --find-links=./install/wheels/ --no-index --force-reinstall
# Pass --reinstall to replace an existing install.
uv pip install "isaacteleop[retargeters,cloudxr,ui]" --find-links=./install/wheels/ --reinstall

Alternative: install directly from source with pip#

The repository also ships a root pyproject.toml using the scikit-build-core backend, which drives the same top-level CMakeLists.txt. This lets you build and install with standard Python tooling, without running the cmake -B build steps yourself; the classic flow above (which CI uses to produce install/wheels/ and the released wheels) is unchanged, so the two coexist.

pip install .            # build + install the compiled wheel from source
pip install -e .         # editable / developer install

Note

The CMake build tree is kept under build-wheel/<cache-tag>/ (e.g. build-wheel/cpython-311/) — one per Python version, so different interpreters never share a configured CMake cache — instead of a temporary directory. Re-installs are therefore incremental. It sits outside build/, so it never collides with a classic cmake -B build tree. Both are gitignored.

What this path does and how it differs from the classic flow:

  • Full build, no overrides. The backend passes no cmake.define overrides, so BUILD_EXAMPLES, BUILD_TESTING, and BUILD_PLUGINS stay at their CMake defaults: a pip install builds the full default target — extensions, examples, C++ tests, and plugins (a plugin without its SDK skips gracefully). It installs only the isaacteleop_wheel and isaacteleop_binaries components, so C++ library/header install rules do not leak into the wheel.

  • clang-format is enforced. Because the gate is left on, the build fails if clang-format-14 is not installed or any C++ file is unformatted — a pip install therefore requires clang-format-14 on Linux.

  • All executables on PATH. Every executable built from src/ and examples/ — example programs, C++ test binaries, plugin tools (oxr_simple_api_demo, se3_printer, schema_tests, …) — is installed into the venv’s bin/ (the wheel’s scripts scheme; see the executable-install loop in the root CMakeLists.txt), so they are on PATH once the venv is active. They statically link the teleop core libraries, so they are self-contained. Shared libraries (Python extension modules, plugin .so) are not executables and are not placed in bin/.

  • ABI. Extensions are compiled against the interpreter that runs the build (so the wheel’s ABI tag matches) and against NumPy 2.x, so a single wheel works with both NumPy 1.x and 2.x at runtime.

  • No type stubs. The pip-built wheel omits the .pyi stubs that the classic and released wheels ship (stub generation shells out to uv, which is not guaranteed inside pip’s build isolation). Imports and runtime behavior are unaffected.

  • Version. The pip-facing version is derived from the VERSION file as MAJOR.MINOR+local — the same value the classic flow produces for a non-CI/local build. The pip path is a from-source/dev build, so it is always tagged +local; the git-aware release versioning (tags, a1 / rc1 / .devN labels) stays with the classic flow via cmake/IsaacTeleopVersion.cmake.

Editable installs and iterating on pure-Python subpackages

An editable install (pip install -e .) never recompiles on import. Pure-Python subpackages resolve straight to src/python/isaacteleop/, so edits take effect live — a fresh interpreter is enough.

Compiled extensions are the exception: .so/.pyd still come from the CMake build tree, so C++ changes need a cmake --build (or a re-run of pip install -e .) first.

See Build System for the full build-system reference.

retargeters extra on aarch64 (Jetson / DGX)

The full retargeters extra does not resolve on aarch64 (some of its pinned dependencies have no aarch64 wheels). On Jetson/DGX-class robotics targets, install the retargeters-lite extra instead:

pip install "isaacteleop[retargeters-lite]"