Building C++ USD Plugins Against the Standalone Installer#

The standalone Isaac Sim installer ships the USD runtime shared libraries (under extscache/omni.usd.libs-*/bin/) and the matching Python bindings, but it does not ship the C++ headers or the pxrConfig.cmake package-config files needed to compile your own native USD plugins. This page describes a supported workflow for obtaining matching headers and linking native plugins against the USD libraries that Isaac Sim loads at runtime.

If you are developing in-tree against a Kit C++ extension template, use the workflow described in CLI extension templates instead. The page below is specifically for building standalone native USD plugins (those discovered and loaded via Plug::Load() at runtime) against an installed Isaac Sim package.

When You Need This#

You need this workflow when you are building a C++ USD plugin that must be loaded into a Isaac Sim process, and you are starting from the standalone installer rather than the source repository.

USD discovers your plugin at runtime by walking PXR_PLUGINPATH_NAME, parsing its plugInfo.json, and then calling Plug::Load(). Plug::Load() performs a normal dlopen() on your shared library, which means your plugin must be ABI-compatible with the USD runtime libraries already loaded in the Isaac Sim process.

Prerequisites#

Inside the standalone installer, locate the bundled packman launcher and the manifest that pins all of Isaac Sim’s external dependencies:

<isaac-sim-install>/kit/dev/tools/packman/packman
<isaac-sim-install>/kit/dev/all-deps.packman.xml

Open all-deps.packman.xml and find the usd-release dependency entry. It contains an inner <package> element whose name and version attributes identify the exact OpenUSD build that Isaac Sim was compiled against — for example:

<dependency name="usd-release">
    <package name="usd.py312.manylinux_2_35_x86_64.stock.release"
             version="0.25.11.kit.2-gl.19811"/>
</dependency>

The name is platform- and Python-version-encoded; copy both attributes verbatim into your own packman project file (see below).

You also need the Python development headers that ship inside the installer:

<isaac-sim-install>/kit/python/include/python3.XX/

The USD Ar and Tf headers transitively include Boost.Python via TfPyObjWrapper, so even a plugin that does not directly call Python must be able to #include <Python.h>.

Pull Matching USD Dev Artifacts With Packman#

Create a small packman project file next to your plugin source — for example, usd-dev.packman.xml:

<project toolsVersion="6.0">
  <!--
    Replace PACKAGE_NAME_FROM_ALL_DEPS and VERSION_FROM_ALL_DEPS with
    the inner <package> element's name and version copied verbatim
    from the usd-release entry in
    <isaac-sim-install>/kit/dev/all-deps.packman.xml.
  -->
  <dependency name="usd-release" linkPath="_deps/usd-release">
    <package name="PACKAGE_NAME_FROM_ALL_DEPS" version="VERSION_FROM_ALL_DEPS"/>
  </dependency>
</project>

Then pull the matching dev artifacts using the packman bundled with the installer:

<isaac-sim-install>/kit/dev/tools/packman/packman pull \
    usd-dev.packman.xml --platform linux-x86_64

After packman pull finishes, _deps/usd-release/ will contain the USD development tree:

_deps/usd-release/
  include/
    pxr/        # OpenUSD C++ headers; in OpenUSD 25.x and later,
                # Boost.Python is vendored under pxr/external/boost/
    tbb/        # TBB headers used by USD
  lib/          # Packman-built USD libraries (do NOT link against these)
  pxrConfig.cmake
  cmake/

Use include/ for compilation. pxrConfig.cmake is shipped in the drop, but it transitively find_dependency()-loads the *Config.cmake files for TBB, MaterialX, Imath, and OpenSubdiv, and the usd-release packman drop does not include them. A plain find_package(pxr REQUIRED) therefore fails to resolve. The recipe in the next section sidesteps this by pointing CMake at include/ directly. Do not link your plugin against the libraries under _deps/usd-release/lib/ — see the next section.

Plugin Source Requirements#

USD’s plugin registration macros (TF_REGISTRY_FUNCTION, TF_REGISTRY_FUNCTION_WITH_TAG) expand at global namespace scope and reference unqualified Tf_RegistryInit and the per-library tag MFB_ALT_PACKAGE_NAME. Two source-level requirements are not optional:

  1. Define three preprocessor macros at compile time, one per plugin target. They identify the plugin to USD’s registry; the values are conventionally the same short name in three case variants. In CMake, this looks like:

    target_compile_definitions(my_usd_plugin PRIVATE
        MFB_PACKAGE_NAME=myUsdPlugin
        MFB_ALT_PACKAGE_NAME=myUsdPlugin
        MFB_PACKAGE_MODULE=MyUsdPlugin
    )
    
  2. Place PXR_NAMESPACE_USING_DIRECTIVE near the top of any translation unit that uses TF_REGISTRY_FUNCTION, so that the unqualified Tf_RegistryInit inside the macro expansion resolves to the OpenUSD inline namespace:

    #include <pxr/pxr.h>
    #include <pxr/base/tf/type.h>
    #include <pxr/usd/ar/resolver.h>
    
    PXR_NAMESPACE_USING_DIRECTIVE
    
    class MyResolver : public ArResolver { /* ... */ };
    
    TF_REGISTRY_FUNCTION(TfType) {
        TfType::Define<MyResolver, TfType::Bases<ArResolver>>();
    }
    

Without either, the plugin will not compile.

Keeping Headers and Runtime In Sync#

OpenUSD encodes its release version in the pxrInternal_v0_* inline namespace. A plugin compiled against one OpenUSD release cannot be loaded into a process that links a different OpenUSD release — the mangled symbol names will not match, and you will see undefined-symbol errors inside Plug::Load().

The OpenUSD version shipped inside Isaac Sim can change across releases. The table below records known mappings; always confirm the exact version by inspecting the usd-release entry inside the all-deps.packman.xml of the installer you are targeting.

Isaac Sim version

OpenUSD version

Inline namespace (pxrInternal_v0_*)

5.1.0

24.05

pxrInternal_v0_24_5__pxrReserved__

6.0.0

25.11

pxrInternal_v0_25_11__pxrReserved__

Caution

The packman approach in this page automatically pulls the matching OpenUSD headers for the installer you target, so you should not need to read the inline-namespace strings yourself. They are listed here only as a diagnostic aid: if you see an undefined symbol that contains pxrInternal_v0_24_5 but your plugin was compiled against pxrInternal_v0_25_11, the headers and runtime are out of sync and the link step is pointing at the wrong USD libraries. Confirm the exact namespace string for your installer with nm -D --defined-only extscache/omni.usd.libs-*/bin/libusd_tf.so | head before relying on this table.