Embedding VEX Header Files Inside an HDA
VEX `#include` cannot resolve `opdef:` URIs, so headers cannot be referenced directly from inside an HDA. Here is the workaround that does work: extract the embedded section on install and add the directory to HOUDINI_VEX_PATH.
Embedding VEX Header Files Inside an HDA
A long-standing question on the SideFX forum (originally posted in 2016, still unanswered as of 2026): can you ship a .h VEX header inside an HDA so the asset stays self-contained?
I tested this on Houdini 21.0.700. Short version: the obvious approach does not work, but there is a clean workaround.
What does not work
You cannot #include an embedded section directly. Every form of the opdef: URI fails inside a wrangle:
#include "opdef:.?myheader.h"
#include "opdef:/Sop/myasset::1.0?myheader.h"
VEX reports Unable to include "opdef:...". The failure is not in the VEX preprocessor — hou.readFile("opdef:...") returns Invalid file name as well, which means the opdef: scheme is simply not registered with the file resolver that VEX #include goes through. It works for parameters that take a filename (textures, geometry caches), but not for VEX includes. SideFX has not bridged this gap in any version up to H21.
What does work
Embed the header as a section, then extract it to a real path on install and prepend that path to HOUDINI_VEX_PATH:
# OnInstall / OnLoaded event handler
import hou, os, tempfile
defn = kwargs["type"].definition()
out_dir = os.path.join(hou.getenv("HOUDINI_USER_PREF_DIR"),
"embedded_vex", defn.nodeType().name())
os.makedirs(out_dir, exist_ok=True)
for name, sec in defn.sections().items():
if name.endswith(".h"):
with open(os.path.join(out_dir, name), "w") as f:
f.write(sec.contents())
old = hou.getenv("HOUDINI_VEX_PATH") or "&"
if out_dir not in old:
hou.hscript(f"setenv HOUDINI_VEX_PATH = {out_dir}{os.pathsep}{old}")
hou.hscript("varchange")
After this, any wrangle — inside or outside the asset — can do:
#include "myheader.h"
and it compiles. I confirmed end-to-end: a function defined in the embedded header was resolved at cook time and produced the expected output.
Caveats
HOUDINI_VEX_PATHis process-global. Two assets that both embedutils.hwill collide — namespace your filenames (myasset_utils.h).- Use a versioned subdirectory (
embedded_vex/<asset>/<version>/) so an updated asset does not clobber a header an older instance still depends on. OnInstallruns once per machine;OnLoadedruns every time the hip is opened. The handler above is idempotent, soOnLoadedis the safer choice.- The same pattern works for OpenCL kernels and any other resource that wants a real file path rather than an inline string.
It is not the answer the original poster wanted — direct opdef: inclusion would be cleaner — but it gives you a single-file .hda that carries its own VEX library, which is what the question was actually asking for.