Skip to content

Patch ITK's znzlib to mangle its symbols, as its niftiio already is - #231

Closed
gdevenyi wants to merge 1 commit into
BIC-MNI:develop-1.9.18from
gdevenyi:itk-znzlib-mangle-patch
Closed

Patch ITK's znzlib to mangle its symbols, as its niftiio already is#231
gdevenyi wants to merge 1 commit into
BIC-MNI:develop-1.9.18from
gdevenyi:itk-znzlib-mangle-patch

Conversation

@gdevenyi

@gdevenyi gdevenyi commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Draft — backup. The real fix is upstream in InsightSoftwareConsortium/ITK#6756. This is the local fallback for as long as that has not landed in the pinned SHA. If it lands, close this and bump the ITK pin instead.

The gap

ITK renames its bundled niftiio symbols to itk_*itk_nifti_mangle.h, included from ITK's nifti1.h, 103 names — but never did the same for znzlib. ITKznz exports the plain names:

Xznzclose  znzdopen  znzeof   znzflush  znzgetc  znzgets  znzopen
znzprintf  znzputc   znzputs  znzread   znzrewind  znzseek  znztell  znzwrite

So every tool here that links ITK next to libminc — c3d, elastix, ANTs, the EZminc tools — carries two definitions of each as soon as the other side's znzlib is unmangled. Nothing fails at link time: ITK's copies are pulled into the executable and land in its dynamic symbol table, where they interpose over the other library's.

Measured with ITK release-4.14's own znzlib.c linked next to a shared system nifti_clib:

ITKznz unmangled exports znz names in exe .dynsym
as pinned 15 8
with this patch 0 0

Is it biting today?

No — and that is worth being precise about. Our own NIfTI is already renamed to minc_*, so nothing currently in the link exports the plain znz names. This is latent.

It becomes active the moment something else brings its own znzlib, which is exactly what USE_SYSTEM_NIFTI does — see #230, which currently has to refuse that combination outright. With this patch (or the upstream one) that restriction can be lifted, which is the point: it is what makes a system NIfTI usable alongside the ITK tools, and therefore what a distribution package would need.

Even without USE_SYSTEM_NIFTI the two have already drifted, so the collision is not merely theoretical: ITK's znzseek/znztell take and return long while nifti_clib 3.x uses znz_off_t, which differ on ILP32 with _FILE_OFFSET_BITS=64 (measured: 4 bytes against 8); and sizeof(struct znzptr) differs between builds that disagree on HAVE_ZLIB.

The change

Mirrors what ITK already does for niftiio, and what we already do for our own NIfTI in libminc/cmake-modules/PatchNiftiMangle.cmake:

  • cmake-modules/itk_znzlib_mangle.h — 15 #defines, generated from the symbols ITK's znzlib.c actually exports.
  • cmake-modules/PatchITKZnzMangle.cmake — drops that header beside ITK's znzlib.h and includes it from there, at the same point nifti1.h includes itk_nifti_mangle.h.
  • PATCH_COMMAND on the ITKv4 ExternalProject_Add, which had none.

znzclose is a macro over Xznzclose, which is mangled, so it expands to the mangled name at the call site. ITK's only consumer, itkNiftiImageIO.cxx, reaches znz through <nifti1_io.h><znzlib.h>, so it picks the mangling up with no further changes.

Verification

Against a tree laid out like the pinned ITK source:

  • patch applies, then reports already patched on a second run (idempotent — PATCH_COMMAND re-runs on re-configure);
  • rebuilding the patched znzlib.c: 15 unmangled exports become 0, 15 itk_* exports appear;
  • if the anchor in znzlib.h ever stops matching, the step exits 1 with an explanation rather than silently doing nothing — verified, as is the missing-source case.

Not verified here: a full ITK build, which is hours. The patch touches one vendored third-party header and adds one file next to it, and ITK's own consumer path goes through that header.

🤖 Generated with Claude Code

https://claude.ai/code/session_019katBUnczdvUS7WQ4RpVoa

ITK renames its bundled niftiio symbols to itk_* (itk_nifti_mangle.h,
included from ITK's nifti1.h) but never did the same for znzlib, so ITKznz
exports the plain names: Xznzclose, znzdopen, znzeof, znzflush, znzgetc,
znzgets, znzopen, znzprintf, znzputc, znzputs, znzread, znzrewind, znzseek,
znztell, znzwrite.

Every tool here that links ITK next to libminc -- c3d, elastix, ANTs, the
EZminc tools -- therefore carries two definitions of each whenever the other
side's znzlib is unmangled. Nothing fails at link time: ITK's copies are
pulled into the executable and land in its dynamic symbol table, where they
interpose over the other library's. Measured against a shared system
nifti_clib: 8 znz names in .dynsym before, none after.

Our own nifti is already renamed to minc_*, so today this is latent rather
than active. It becomes active the moment anything else in the link brings
its own znzlib -- which is exactly what USE_SYSTEM_NIFTI would do.

Apply the missing half at the source, mirroring what ITK already does for
niftiio: drop itk_znzlib_mangle.h beside znzlib.h and include it from there,
at the same point nifti1.h includes its counterpart. The patch step is
idempotent and fails loudly if the pinned ITK stops matching, rather than
silently doing nothing.

Submitted upstream as InsightSoftwareConsortium/ITK#6756. This is the local
fallback for as long as that has not landed in the pinned SHA; drop both
files and the PATCH_COMMAND once it has.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019katBUnczdvUS7WQ4RpVoa
@gdevenyi

gdevenyi commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Superseded — InsightSoftwareConsortium/ITK#6756 merged to release-4.14 on 2026-08-05, so the fix is upstream and this local patch is unnecessary.

#230 bumps the pin instead: cae3eb956073b968. Those are the only two commits in between — the fix and its merge — so the bump carries nothing else.

Verified against the new tarball:

  • ITK's znzlib.c builds to 15 itk_* exports and 0 unmangled.
  • A program linking it next to a shared system nifti_clib exports 0 znz names in its dynamic symbol table, where the old pin put 8.
  • ITK's own CI passed on Linux, Windows and macOS.

The upshot is what this PR was for: USE_SYSTEM_NIFTI and MT_BUILD_ITK_TOOLS no longer collide, so #230 drops the FATAL_ERROR that refused the combination, and all four permutations configure.

Deleting the branch; the approach is preserved here if a future pin ever needs to move backwards.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant