Building an App#
A Kit file (ends in .kit
) defines an Omniverse App. Kit files behave as a single-file extension. The format is the same as an extension.toml
and all runtime behavior is the same. It can be published, downloaded, versioned, and it can have dependencies.
Building an Omniverse App is as simple as listing the extensions that it should contain (extension dependencies) and the default settings to apply.
Simple App#
Here is an example of a very simple app with a dependency and setting applied: repl.kit
:
[dependencies]
"omni.kit.console" = {}
[settings]
exts."omni.kit.console".autoRunREPL = true
Pass the repl.kit
file to the Kit executable:
> kit.exe repl.kit
and it will enable a few extensions (including dependencies) to run a simple REPL.
Application Dependencies Management#
There are conceptual differences when specifying dependencies for an extension vs an app, although the syntax is the same:
For extensions, dependencies are specified as broadly as possible. Versions describe compatibility with other extensions. Your extension can be used in many different apps with different extensions included.
An app is the final leaf on a dependency chain, and is an end-product. All versions of dependencies must be locked in the final package, and in the version control system. That helps to guarantee reproducible builds for end users and developers.
If you pass an app to the Kit executable, it will first resolve all extension versions (either locally or using the registry system), and will then enable the latest compatible versions. Next time you run the app, someone may have published a newer version of some extension and you may get a different result.
You also don’t often have a clear view of the versions chosen, because one extension brings in other extensions that they depend on, and so on. That builds a tree of N-order dependencies.
To lock all dependencies we want to write them back to the kit file. You can manually specify each version of each dependency with exact=true
and lock all of them, but that would be very tedious to maintain. It would also make upgrading to newer versions very difficult.
To address this, Kit has a mode where it will write a dependency solution (of all the resolved versions) back to the tail of the kit file it was launched from.
It will look something like this:
########################################################################################################################
# BEGIN GENERATED PART (Remove from 'BEGIN' to 'END' to regenerate)
########################################################################################################################
# Date: 09/15/21 15:50:53 (UTC)
# Kit SDK Version: 103.0+master.58543.0643d57a.teamcity
# Kit SDK dependencies:
# carb.audio-0.1.0
# carb.windowing.plugins-1.0.0
# ...
# Version lock for all dependencies:
[settings.app.exts]
enabled = [
"omni.kit.asset_converter-1.1.36",
"omni.kit.tool.asset_importer-2.3.12",
"omni.kit.widget.timeline_standalone-103.0.7",
"omni.kit.window.timeline-103.0.7",
]
########################################################################################################################
# END GENERATED PART
########################################################################################################################
On top of that, we have a repo tool: repo_precache_exts
. You specify a list of kit files in repo.toml
to run Kit in that mode on:
[repo_precache_exts]
# Apps to run and precache
apps = [
"${root}/source/apps/omni.app.my_app.kit"
]
Besides locking the versions of all extensions, it will also download/precache them for packaging.
Usually, that tool runs as one of the first steps of the build process. To run it explicitly call:
> repo.bat precache_exts -c release
By default, extensions are cached into the _build/$platform/$config/extscache
folder.
For more config options check repo_tools.toml
file in the kit-kernel
package. It is typically located in _build/$platform/$config/kit/dev/repo_tools.toml
.
The version-lock is written at the tail of the kit file and the changed kit file can then be committed to version-control.
Updating Version Lock#
To update version lock to the latest compatible versions of extensions run: repo build -u
or repo precache_exts -u
.
To update only subset of extensions run: repo precache_exts -u [ext1] [ext2] ...
(repo build -u
does not support that).
Check repo precache_exts -h
for more information.
Longer explanation: You can remove the generated part of the kit file and run the build or precache tool. That will write it again. But if you did run it before you already downloaded extensions in _build/$platform/$config/extscache
, then those local versions of extensions will still be selected again, because local versions are preferred. Before doing that, this folder needs to be cleared. To automate this process, the precache tool has a -u
/ --update
flag. Combination of repo_build
and repo_kit_tools
allow propagation of -u
flag from repo build
to repo precache_exts
.
Build-time extension dependencies#
Precache tool runs before the build, so downloaded extensions can be used during the build. However, extscache
dir contains extension and version for each extension, making it harder to refer to. For that we have a separate dir extsbuild
where we folder link selected extensions by name:
# Link selected extensions into a separate folder without a version. Used for build-time referencing extensions.
# Wildcards are supported in the list.
links.path = "${root}/_build/${platform}/${config}/extsbuild"
links.exts.include = [
"omni.graph.tools",
"omni.ui",
"omni.kit.renderer.imgui",
"omni.kit.test",
"omni.usd.core",
"omni.usd.libs",
]
In premake, you can refer to them using extsbuild_dir
variable, e.g.:
libdirs { extsbuild_dir .. "/omni.usd.core/bin" }
You can add more extensions to be linked in repo.toml
:
links.exts.include."++" = ["omni.foo", "omni.bar"]
Version Specification Recommendations#
The general advice is to write the dependencies required-versions for apps the same way as for extensions, in an open-ended form, like:
[dependencies]
"omni.kit.tool.asset_importer" = {}
or say, locking only to a major-version (Semantic Versioning is used):
[dependencies]
"omni.kit.tool.asset_importer" = { version = "^2.0.0" }
Then the automatic version lock will select 2.0.0
, 2.0.1
, 2.1.0
, 2.99.99
for you, but never 3.0.0
.
You can also review the git diff at that point, to see which versions actually changed when the selection process ran.
Windows or Linux only dependencies#
Version locks, and all versions, are by default defined as cross-platform. While we build them only on your current platform, we assume that the same app will run on other platforms. If you need to have an extension that is for a single platform only, you can explicitly specify the version in this way:
[dependencies."filter:platform"."windows-x86_64"]
"omni.kit.window.section" = { version = "102.1.6", exact = true }
Dependencies specified as exact are not written into an automatic version lock. This way, you lock the version manually, and only for the selected platform.
Caching extensions disabled by default#
Often an app has extensions that are packaged with the application, but disabled by default. Base Editor is an example of that. We still want to lock all the versions, and download them, but we can’t put them into the main app kit file, as it will enable them on startup. The solution is simple: use a separate kit file, which includes the main one. For instance, the Base Editor project has:
omni.app.editor.base.kit
and omni.app.editor.full.kit
. The latter includes the former in its dependencies but adds extra extensions. Both kit files are passed to the precache tool (specified in repo.toml
).
Deploying an App#
Kit files fully describe how to run an app, and also are interpreted as an extension. This means that it can be versioned and published into the registry like any other extension. Any Kit app can be found in the extension manager. Click Launch, and the app will be run.
It can also just be shared as a file, and anyone can pass it to kit.exe
or associate it with Kit and just use a mouse double-click to open it.
In practice, we deploy apps with both Kit and all of the dependent extensions downloaded ahead of time. So a packaged application is basically:
Kit file (1 or more)
Precached extensions
Kit SDK
The Kit SDK is already shared between apps using the thin-packaging feature. In the future, we can get to a point where you only need to publish a single Kit file to define an Omniverse App of any complexity. This goal guides and explains certain decisions described in the guide.
Extensions without an App#
Many repositories contain only extensions without publishing an app. However, all their dependencies should be downloaded at build time and version locked.
You don’t have to create a kit file for them, precache tool will do it by default using generated_app_path = "${root}/source/apps/exts.deps.generated.kit"
setting. In this location, a kit file with all extensions will be automatically generated.
exts.deps.generated.kit
- is an app, that contains all extensions from the repo as dependencies. It is used to:
Lock all versions of their dependencies (reproducible builds).
Precache (download) all dependencies before building.
This file is regenerated if:
Any extension is added or removed from the repo.
Any extension version is updated
This file is removed.
It also includes test dependencies, if any.
To update version lock the same repo build -u
flag can be used.
As any other kit file with a version lock it should be committed to the version control to produce reproducible builds.
To disable this feature set a generated app path to empty generated_app_path = ""
.
Supported Targets Check#
Sometimes, by mistake, a new extension version is published, but not for all platforms. For example only for Windows or only for release build.
When precaching (downloading extensions) we can check that each extension has all packages for all supported targets (platforms/configs). That allows catching such mistakes early, rather than finding out about them when building on a different host platform.
It is controlled with those settings, that by default are:
app.extensions.supportedTargets.verify = false
app.extensions.supportedTargets.platform = ["windows-x86_64", "linux-x86_64"]
app.extensions.supportedTargets.config = ["debug", "release"]
The check can be enabled with app.extensions.supportedTargets.verify = true
, then if the package is missing for any of the supported targets, precaching will fail with an error like:
[Error] [omni.ext.plugin] Supported targets check failed. Extension: [omni.foo-1.2.3] missing package for platform: windows-x86_64, config: debug
Other Precache Tool Settings#
As with any repo tool, to find more settings available for the precache tool, look into its repo_tools.toml
file. Since it comes with Kit, this file is a part of the kit-sdk
package and can be found at: _build/$platform/$config/kit/dev/repo_tools.toml