Packages

Prebuilt, per-triplet USD scene-description runtime (OpenUSD v26.05, monolithic usd_ms) shipped as an Elixir/Hex package.

Current section

Files

Jump to
stage_runtime build_openusd.py
Raw

build_openusd.py

#!/usr/bin/env python3
"""Standalone OpenUSD build driver (no SCons).
Ported from fabric-flow-openusd/scons/openusd.py: clones OpenUSD at the pinned
version, patches build_usd.py for the VS2026 generator, and runs OpenUSD's own
build_usd.py with the monolithic / no-python runtime flags. Driven by the
Makefile (elixir_make) so the whole thing stays Elixir-native.
Usage:
python3 build_openusd.py --build-dir <out> [--with-python] [--release]
Env:
OPENUSD_VERSION USD version/tag without the leading 'v' (default 26.05)
USE_SCCACHE when truthy, route OpenUSD's CMake compiles through sccache
"""
import argparse
import os
import shutil
import subprocess
import sys
import sysconfig
import tarfile
def platform_name():
if sys.platform.startswith("win"):
return "windows"
if sys.platform == "darwin":
return "macos"
return "linux"
def patch_vs2026(open_usd_path):
"""Add VS2026 generator support to the cloned build_usd.py (idempotent)."""
build_usd = os.path.join(open_usd_path, "build_scripts", "build_usd.py")
if not os.path.isfile(build_usd):
return
with open(build_usd, encoding="utf-8") as f:
src = f.read()
if "IsVisualStudio2026OrGreater" in src:
return
patch = os.path.join(os.path.dirname(os.path.abspath(__file__)),
"patches", "openusd-vs2026-generator.patch")
if os.path.isfile(patch):
if subprocess.run(["git", "apply", "-p1", patch], cwd=open_usd_path).returncode == 0:
return
patched = src.replace(
"def IsVisualStudio2022OrGreater():",
"def IsVisualStudio2026OrGreater():\n"
" VISUAL_STUDIO_2026_VERSION = (14, 50)\n"
" return IsVisualStudioVersionOrGreater(VISUAL_STUDIO_2026_VERSION)\n"
"def IsVisualStudio2022OrGreater():",
1,
).replace(
' if IsVisualStudio2022OrGreater():\n'
' generator = "Visual Studio 17 2022"',
' if IsVisualStudio2026OrGreater():\n'
' generator = "Visual Studio 18 2026"\n'
' elif IsVisualStudio2022OrGreater():\n'
' generator = "Visual Studio 17 2022"',
1,
)
if patched != src:
with open(build_usd, "w", encoding="utf-8") as f:
f.write(patched)
def build_python_info(plat):
"""(executable, include_dir, library, version) for --build-python-info,
pointing LIBRARY at the shared libpython that actually exists (conda's
sysconfig otherwise reports a static .a it doesn't ship)."""
version = sysconfig.get_config_var("py_version_short")
include_dir = sysconfig.get_path("include")
libdir = sysconfig.get_config_var("LIBDIR") or ""
if plat == "windows":
nodot = sysconfig.get_config_var("py_version_nodot")
candidates = [os.path.join(sys.base_prefix, "libs", f"python{nodot}.lib")]
elif plat == "macos":
candidates = [os.path.join(libdir, f"libpython{version}.dylib")]
else:
candidates = [os.path.join(libdir, f"libpython{version}.so")]
library = next((c for c in candidates if os.path.exists(c)), candidates[0])
return [sys.executable, include_dir, library, version]
def windows_msvc_env():
"""Return the environment set by vcvars64.bat so build_usd.py finds cl."""
vswhere = r"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"
if not os.path.exists(vswhere):
raise RuntimeError("vswhere.exe not found")
vs_path = subprocess.check_output(
[vswhere, "-latest", "-products", "*",
"-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
"-property", "installationPath"], encoding="utf-8").strip()
if not vs_path:
raise RuntimeError("No Visual Studio with the required VC tools found")
vcvars = os.path.join(vs_path, "VC", "Auxiliary", "Build", "vcvars64.bat")
output = subprocess.check_output(f'"{vcvars}" >nul && set', shell=True, text=True)
env = {}
for line in output.splitlines():
if "=" in line:
k, v = line.split("=", 1)
env[k.upper()] = v
return env
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--build-dir", required=True, help="OpenUSD install prefix")
ap.add_argument("--with-python", action="store_true",
help="build with Python (only needed to obtain usdGenSchema)")
ap.add_argument("--release", action="store_true",
help="release build variant (else relwithdebuginfo)")
ap.add_argument("--package", action="store_true",
help="after building, tar.gz the build dir to OPENUSD_ARCHIVE")
args = ap.parse_args()
version = os.environ.get("OPENUSD_VERSION", "26.05")
plat = platform_name()
src = f"openusd-{version}-src"
if not os.path.exists(src):
print(f"Cloning OpenUSD v{version} ...", flush=True)
rc = subprocess.run([
"git", "clone", "-b", "v" + version, "--recursive", "--depth", "2",
"https://github.com/PixarAnimationStudios/OpenUSD.git", src]).returncode
if rc != 0:
sys.exit(f"OpenUSD clone failed ({rc})")
patch_vs2026(src)
lib = {
"windows": f"{args.build_dir}/lib/usd_ms.dll",
"macos": f"{args.build_dir}/lib/libusd_ms.dylib",
}.get(plat, f"{args.build_dir}/lib/libusd_ms.so")
if os.path.exists(lib):
print(f"OpenUSD already built at {args.build_dir}", flush=True)
if args.package:
package(args.build_dir)
return
env = {}
if plat == "windows":
env.update(windows_msvc_env())
else:
env["PATH"] = os.environ.get("PATH", "")
for k, v in os.environ.items():
if k.startswith(("SCCACHE_", "ACTIONS_")) or k == "USE_SCCACHE":
env[k] = v
cmake_args = "-DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DCMAKE_CXX_STANDARD=17"
use_sccache = os.environ.get("USE_SCCACHE", "") not in ("", "0", "no", "false")
sccache = shutil.which("sccache") if use_sccache else None
if sccache:
launcher = sccache.replace("\\", "/")
cmake_args += (f' -DCMAKE_C_COMPILER_LAUNCHER="{launcher}"'
f' -DCMAKE_CXX_COMPILER_LAUNCHER="{launcher}"')
print(f"sccache enabled: {sccache}", flush=True)
python = "python3" if shutil.which("python3") else "python"
cmd = [
python, f"{src}/build_scripts/build_usd.py", args.build_dir, "--verbose",
"--build-variant", "release" if args.release else "relwithdebuginfo",
"--build-monolithic",
"--python" if args.with_python else "--no-python",
"--no-examples", "--no-tutorials", "--no-tools", "--no-debug-python",
"--no-openvdb", "--no-usdview", "--no-imaging", "--no-vulkan",
"--no-materialx", "--onetbb",
"--no-compiler-cache" if sccache else "--compiler-cache",
"--cmake-build-args", cmake_args,
]
if args.with_python:
cmd += ["--build-python-info", *build_python_info(plat)]
print("Building OpenUSD ...", flush=True)
rc = subprocess.run(cmd, env=env).returncode
if rc != 0:
sys.exit(f"OpenUSD build failed ({rc})")
if args.package:
package(args.build_dir)
# build_usd.py's install prefix also holds the dependency source (`src/`) and
# build-intermediate (`build/`) trees — huge on Windows (MSVC .obj/.pdb). Ship
# only the installed SDK.
_PACKAGE_SKIP = {"src", "build"}
def package(build_dir):
"""tar.gz the installed OpenUSD SDK from build_dir into OPENUSD_ARCHIVE (so
extracting yields include/, lib/, plugin/, bin/, share/, cmake/ at the root),
excluding the dependency source/build-intermediate trees."""
archive = os.environ.get("OPENUSD_ARCHIVE")
if not archive:
sys.exit("OPENUSD_ARCHIVE not set; cannot package")
os.makedirs(os.path.dirname(os.path.abspath(archive)), exist_ok=True)
print(f"Packaging {build_dir} -> {archive}", flush=True)
with tarfile.open(archive, "w:gz") as tar:
for entry in sorted(os.listdir(build_dir)):
if entry in _PACKAGE_SKIP:
continue
tar.add(os.path.join(build_dir, entry), arcname=entry)
if __name__ == "__main__":
main()