Agent:claude-jitfields-to-fastfields
libfastfields-cuda.so is built from a MODULES list that omits four of the eleven .cpp files present in the CUDA library. The hub calls into those four unconditionally on the CUDA path, so 11 public CUDA entry points resolve to nothing at runtime — while both the CUDA compile and the hub link report success.
Evidence
fastfields-cuda-lib/Makefile (2b2ad55), MODULES:
distance reg_field reg_field_rls reg_flow reg_flow_rls pushpull pushpull_backward
Source files actually present in that repo:
distance.cpp posdef.cpp pushpull.cpp pushpull_backward.cpp reg_field.cpp
reg_field_rls.cpp reg_flow.cpp reg_flow_rls.cpp resize.cpp restrict.cpp splinc.cpp
posdef.cpp, resize.cpp, restrict.cpp, splinc.cpp are never compiled and never linked into the shared object. Their headers (posdef.h, resize.h, restrict.h, splinc.h) are shipped, so every consumer compiles cleanly against declarations that have no definition.
Contrast fastfields-cpu-lib, whose MODULES lists all ten of its .cpp files — the gap is CUDA-only.
The 11 dead symbols
The hub calls each of these directly under #ifdef FF_WITH_CUDA / if (IS_CUDA(...)) — these are real dispatches, not throw-stubs:
| hub file | call |
|---|
posdef.cpp | FF_CUDA::sym_matvec, sym_matvec_backward, sym_addmatvec_, sym_submatvec_, sym_solve, sym_solve_, sym_invert, sym_invert_ |
resize.cpp | FF_CUDA::resample |
restrict.cpp | FF_CUDA::restriction |
splinc.cpp | FF_CUDA::spline_coeff |
e.g. posdef.cpp:22-25:
require_same_device(out, hessian, inp);
#ifdef FF_WITH_CUDA
if (IS_CUDA(out))
returnFF_CUDA::sym_matvec(out, hessian, inp, stream);
So a FF_WITH_CUDA build of libfastfields.so on GPU input reaches an undefined symbol for the whole Posdef family and all of Resampling.
Why CI never caught it
Two independent reasons, and both need fixing:
- The hub links without
-Wl,--no-undefined.Makefile:113 is CUDA_LDFLAGS = -L$(BUILDDIR)/lib -lfastfields-cuda, and the link line at :218 adds no --no-undefined. Undefined symbols in a shared object are legal by default, so ld is silent and the build is "green". - No GPU in CI, so nothing ever loads the library and calls these paths. Per the accepted CUDA policy (shared kernel math is CPU-tested; CUDA-only glue is validated by compile+link), compile+link is the bar — which makes it important that the link is actually strict enough to be a bar.
This is not a kernel-math bug: the fastfields-cuda-impl headers for these four modules exist and compile. It is purely a build-system omission.
Proposed fix
- Add
posdef, resize, restrict, splinc to the CUDA MODULES. - Add
-Wl,--no-undefined to the hub's CUDA link so a future omission fails the build instead of deferring to runtime. - Confirm nvcc peak memory still fits the runner. The existing
MODULES split is deliberate — the comment above it records that ptxas peaks at ~3.8 GB per split module vs ~6–7 GB combined, and that a 16 GB runner survives -j2 only in the split form. These four modules are far lighter than reg_field, but the addition should be measured, not assumed, and the -O1 CI setting kept.
Scope note
FF_CUDA::field_cg is not part of this: solve_field.cpp:42 deliberately throws "fastfields: field_cg is not implemented on CUDA yet" rather than dispatching, so it is honest and link-safe. CUDA CG/FMG remains tracked by #34.
Timing
Filed here rather than on fastfields-cuda-lib because that repo is being folded into this one by the consolidation; post-consolidation the paths become src/lib-cuda/ and the CUDA module list moves into the corresponding make/ fragment. Whoever fixes this should apply it to the consolidated layout, not the pre-consolidation one.
Agent:
claude-jitfields-to-fastfieldslibfastfields-cuda.sois built from aMODULESlist that omits four of the eleven.cppfiles present in the CUDA library. The hub calls into those four unconditionally on the CUDA path, so 11 public CUDA entry points resolve to nothing at runtime — while both the CUDA compile and the hub link report success.Evidence
fastfields-cuda-lib/Makefile(2b2ad55),MODULES:Source files actually present in that repo:
posdef.cpp,resize.cpp,restrict.cpp,splinc.cppare never compiled and never linked into the shared object. Their headers (posdef.h,resize.h,restrict.h,splinc.h) are shipped, so every consumer compiles cleanly against declarations that have no definition.Contrast
fastfields-cpu-lib, whoseMODULESlists all ten of its.cppfiles — the gap is CUDA-only.The 11 dead symbols
The hub calls each of these directly under
#ifdef FF_WITH_CUDA/if (IS_CUDA(...))— these are real dispatches, not throw-stubs:posdef.cppFF_CUDA::sym_matvec,sym_matvec_backward,sym_addmatvec_,sym_submatvec_,sym_solve,sym_solve_,sym_invert,sym_invert_resize.cppFF_CUDA::resamplerestrict.cppFF_CUDA::restrictionsplinc.cppFF_CUDA::spline_coeffe.g.
posdef.cpp:22-25:So a
FF_WITH_CUDAbuild oflibfastfields.soon GPU input reaches an undefined symbol for the whole Posdef family and all of Resampling.Why CI never caught it
Two independent reasons, and both need fixing:
-Wl,--no-undefined.Makefile:113isCUDA_LDFLAGS = -L$(BUILDDIR)/lib -lfastfields-cuda, and the link line at:218adds no--no-undefined. Undefined symbols in a shared object are legal by default, soldis silent and the build is "green".This is not a kernel-math bug: the
fastfields-cuda-implheaders for these four modules exist and compile. It is purely a build-system omission.Proposed fix
posdef,resize,restrict,splincto the CUDAMODULES.-Wl,--no-undefinedto the hub's CUDA link so a future omission fails the build instead of deferring to runtime.MODULESsplit is deliberate — the comment above it records thatptxaspeaks at ~3.8 GB per split module vs ~6–7 GB combined, and that a 16 GB runner survives-j2only in the split form. These four modules are far lighter thanreg_field, but the addition should be measured, not assumed, and the-O1CI setting kept.Scope note
FF_CUDA::field_cgis not part of this:solve_field.cpp:42deliberately throws"fastfields: field_cg is not implemented on CUDA yet"rather than dispatching, so it is honest and link-safe. CUDA CG/FMG remains tracked by #34.Timing
Filed here rather than on
fastfields-cuda-libbecause that repo is being folded into this one by the consolidation; post-consolidation the paths becomesrc/lib-cuda/and the CUDA module list moves into the correspondingmake/fragment. Whoever fixes this should apply it to the consolidated layout, not the pre-consolidation one.