ADR-0200: Move volk -include flag off of volk_dep.compile_args (libvmaf.pc leak fix)¶
- Status: Accepted
- Date: 2026-04-27
- Deciders: Lusoris, Claude (Anthropic)
- Tags: vulkan, build, fork-local, abi
- Supersedes: nothing — bug-fix follow-up to ADR-0198
Context¶
ADR-0198 renamed volk's vk* PFN dispatcher symbols to vmaf_priv_vk* via a force-included header (volk_priv_remap.h), generated by the volk subproject's gen_priv_remap.py from upstream volk.h. The -include flag was attached to volk_dep's compile_args so every libvmaf TU pulling in volk_dep (i.e., libvmaf's vulkan kernels) picked it up.
That works for shared libvmaf.so builds — meson's pkg-config generator drops dependency compile_args from the public Cflags: on shared targets. It does not work for static libvmaf.a builds: meson includes compile_args from all dependencies in the generated libvmaf.pc's Cflags: so downstream consumers know how to link against the static archive's transitively-required deps.
Net effect on libvmaf.pc from a default_library=static -Denable_vulkan=enabled build:
Cflags: -I${includedir} -I${includedir}/libvmaf -DVK_NO_PROTOTYPES \
-include /<libvmaf-build-dir>/subprojects/volk-vulkan-sdk-1.4.341.0/volk_priv_remap.h \
-pthread
Lawrence's BtbN-style fully-static FFmpeg build (cross-toolchain, x86_64-ffbuild-linux-gnu-gcc, glibc-2.28) ran:
$ pkg-config --cflags libvmaf
-I/opt/ffbuild/include/libvmaf -DVK_NO_PROTOTYPES \
-include /45-vmaf/lusoris/core/build/subprojects/volk-vulkan-sdk-1.4.341.0/volk_priv_remap.h \
-pthread
After libvmaf was installed to /opt/ffbuild/, the build-dir path was gone. FFmpeg's configure ran check_func_headers aom/aom_codec.h with the leaked Cflags, hit:
<command-line>: fatal error: \
/45-vmaf/lusoris/core/build/subprojects/volk-vulkan-sdk-1.4.341.0/volk_priv_remap.h: \
No such file or directory
compilation terminated.
The whole FFmpeg build cascaded: every subsequent feature probe that included libvmaf's Cflags failed the same way. lawrence's chat report 2026-04-27 22:19: "thats a bug for sure" / 22:20: "yeah because it's broken the compile flags probably lol".
Decision¶
Move the -include volk_priv_remap.h flag off of volk_dep.compile_args and onto libvmaf's own targets as private c_args. The volk subproject continues to expose volk_priv_remap_h_path as a meson variable; the parent project (libvmaf) reads it via subproject('volk').get_variable('volk_priv_remap_h_path') and appends ['-include', volk_priv_remap_h_path] to vmaf_cflags_common, which is the c_args: argument of libvmaf's library() call (and the various sub-libraries that compile vulkan TUs).
Per meson's pkg-config generator: c_args: on a library() is private to the target and does not appear in the generated .pc Cflags:. Only compile_args: declared on a dependency that the target consumes appears in Cflags:. By moving the -include from a dependency to private c_args, the symbol-rename behaviour stays identical at libvmaf's compile time while the leaked path is removed from the public Cflags surface.
volk_dep keeps -DVK_NO_PROTOTYPES in compile_args because that flag is harmless to consumers — it's a behaviour switch for volk's header that just disables auto-prototype declarations. Consumers don't include volk.h directly, so it has no effect on them either way.
Alternatives considered¶
| Option | Pros | Cons | Why not chosen |
|---|---|---|---|
Move -include to libvmaf's c_args (chosen) | Surgical; keeps the rename behaviour byte-for-byte; no consumer-visible change to libvmaf.pc on shared builds; static libvmaf.pc Cflags now have no leaked paths | Requires libvmaf to know about the volk subproject's variable | Cleanest meson-idiomatic fix |
Manually edit libvmaf.pc post-generation to strip the -include line | Minimal volk-side change | Brittle (regex-based); fragile across meson versions; works for Cflags: but not for Cflags.private: | Hack — easier to fix at the source |
Generate volk's volk_priv_remap.h at install time instead of build time | Avoids build-dir paths in pkg-config | volk's wrap is a build artefact, not an install artefact; no place to install the generated header on the target system; would also leak -include /usr/include/vmaf/volk_priv_remap.h to consumers who never need it | Architecturally wrong — the rename is a private libvmaf detail, never a consumer concern |
Bake the rename into volk.c source via a script-edit at configure time, drop the runtime -include entirely | No -include flag anywhere | Fragile — regenerating volk.c on every wrap bump is a maintenance burden; loses the regex-based generator's coverage signal (gen script prints rename count) | Over-engineering for a flag-leak bug |
| Drop the per-build-mode distinction by always producing shared libvmaf | Avoids the static-build pkg-config mechanic | BtbN-style FFmpeg builds REQUIRE static libraries; that's the whole point of the fork-local Vulkan support for that workflow | Out of scope — static support is a load-bearing feature |
Consequences¶
- Positive: lawrence's BtbN-style fully-static FFmpeg build works again.
pkg-config --cflags libvmafreturns-I${includedir} -I${includedir}/libvmaf -DVK_NO_PROTOTYPES -pthread(no leaked build-dir paths) on both shared and static builds. - Positive: the symbol-rename behaviour is unchanged — verified via
nm libvmaf.a | grep -cE '^[0-9a-f]* (T|D|B|R) vk[A-Z]'=0(no GLOBALvk*) andnm libvmaf.a | grep -cE '^[0-9a-f]* (T|D|B|R) vmaf_priv_vk'=719post-fix; identical to ADR-0198's pre-leak-fix numbers. - Negative: the libvmaf side now has a 3-line block coupling it to a volk-subproject internal variable. Documented at the declaration site so future maintainers see the dependency.
- Neutral / follow-ups:
- Add a CI assertion that the static-build
libvmaf.pcdoes not containvolk_priv_remapor any${meson.build_root()}substring. Cheap regression gate. - If a future libvmaf restructuring splits the vulkan kernels into a separate
static_library('vmaf_vulkan_internal'), move the-includeonto that library'sc_args:instead of the umbrellavmaf_cflags_commonto scope it more tightly. Not load-bearing today.
References¶
- Source: lawrence's chat report 2026-04-27 22:19 — pasted FFmpeg configure log showing the leaked path.
- Pre-fix verification (this dev box):
$ grep Cflags core/build-vk-static-test/meson-private/libvmaf.pc
Cflags: -I${includedir} -I${includedir}/libvmaf -DVK_NO_PROTOTYPES \
-include /home/kilian/dev/vmaf/core/build-vk-static-test/subprojects/.../volk_priv_remap.h \
-pthread
- Post-fix verification: