Portable Build Runtime Paths
Purpose
Treat relocation as a build contract. A produced binary should run from documented build and install layouts without relying on the developer's current directory, home directory, username, shell setup, or stale environment variables.
Workflow
Define the runtime layout.
- Name the supported layouts: build tree, install tree, copied artifact folder, package bundle, plugin folder, or source checkout.
- List every runtime dependency: shared libraries, plugins, shaders/SPIR-V, kernels, USD files, textures, config, Python modules, licenses, and helper executables.
- Decide which paths are user inputs and which are packaged resources.
Choose stable anchors.
- Resolve packaged resources relative to the executable, shared library, plugin, package root, or an explicit
--resource-dir/config value. - Resolve scene-authored assets relative to the authored layer or scene context, not process
cwd. - A loader that discovers sidecar assets (materials, textures) by recursively walking the scene directory breaks when the scene lives in a shared system dir (e.g.
/tmp): it ingests hundreds of unrelated files and a ~170 ms load becomes seconds. Prefer parsing explicit USD references; if you must scan, bound it to the scene directory, gate it behind a cheap "any candidate files here?" check, and provide an environment opt-out. - Use process
cwdonly for user-provided relative paths and document that policy in CLI help.
- Resolve packaged resources relative to the executable, shared library, plugin, package root, or an explicit
Make dynamic linking relocatable.
- Prefer build/install RPATHs based on
$ORIGINon Linux,@loader_path/@rpathon macOS, and app-local DLL search layout on Windows. - Do not bake absolute home, workspace, conan-cache, VM, or username paths into release artifacts unless the artifact is explicitly nonportable.
- Keep
LD_LIBRARY_PATH,DYLD_LIBRARY_PATH, and shell setup scripts as developer conveniences, not required runtime contracts.
- Prefer build/install RPATHs based on
Make generated resources real build outputs.
- Compile shaders, codegen outputs, and copied resources through build-system targets with declared inputs, outputs, and dependencies.
- Install or package those outputs beside the binary or under a predictable resource directory.
- Avoid hard-coded build-tree strings such as
build/foo.spv; compute the path from the chosen runtime anchor.
Fail loudly and usefully.
- On missing resources or libraries, report the exact path tried, the runtime anchor used, and the override flag or environment variable if one exists.
- Include
--helpoutput for resource-path overrides when the binary supports them. - Do not hide portability failures by silently falling back to source-tree paths unless that is an explicitly documented dev mode.
Prove relocation.
- Run
--helpand one smoke command from a directory outside the repo. - Run at least one smoke after
cmake --installor equivalent packaging. - Copy or move the install/artifact directory to a temporary path with a different parent name and run again.
- For path bugs, test from repo root, build dir,
/tmp, and a path that does not resemble the developer's checkout.
- Run
Checks
Useful checks when available:
readelf -d path/to/binary
ldd path/to/binary
otool -L path/to/binary
cmake --install build --prefix /tmp/app-install
For CLI tools, prefer smoke commands shaped like:
(cd /tmp && /tmp/app-install/bin/tool --help)
(cd /tmp && /tmp/app-install/bin/tool --scene /absolute/scene.usda --output /tmp/out.ppm)
Review Checklist
- Does the binary run when launched from a different
cwd? - Does the installed artifact run without source-tree files present?
- Are RPATH/RUNPATH entries relative to the artifact, not absolute to a user's checkout?
- Are shaders, plugins, kernels, and other generated resources declared as build and install outputs?
- Are user-provided relative paths resolved consistently and separately from packaged resources?
- Are scene assets resolved through the scene/layer context rather than accidental process
cwd? - Do errors print the resolved path that failed?
Anti-Patterns
- Opening packaged files with bare relative paths like
build/foo.spvorshaders/foo.spv. - Fixing local runs by requiring users to launch from the repo root.
- Shipping binaries that only work with a developer's
LD_LIBRARY_PATH. - Treating RPATH repair tools as the primary build design instead of fixing CMake/install rules.
- Letting tests pass because source-tree fallback masks missing installed resources.
- Copying libraries from another machine without verifying embedded runtime paths.
Handoff
Report:
- Supported runtime layouts.
- Resource anchor and override policy.
- RPATH/library lookup strategy.
- Install/package files added or changed.
- Relocation smoke commands and outcomes.
- Remaining nonportable assumptions, if any.