Skip to content

image: find ImageMagick's coders beside its own DLL; init it before every Magick++ use - #673

Merged
transfix merged 1 commit into
masterfrom
fix/magick-coders-beside-magickcore
Oct 18, 2026
Merged

transfix merged 1 commit into
masterfrom
fix/magick-coders-beside-magickcore

Conversation

@transfix

Copy link
Copy Markdown
Owner

Why

On this Windows dev box, three tests always failed, and we had been writing them off as "ImageMagick has no decode delegate here": ImageTest.ReadsCmykInputAsRgb, CvcCliTest.Vol2ImgExportsSlices and CvcCliTest.Img2VolImportsSlices. They failed for three separate reasons. CI only passed because its Windows test step exports MAGICK_CODER_MODULE_PATH, MAGICK_FILTER_MODULE_PATH and MAGICK_CONFIGURE_PATH.

  1. libcvc looked for ImageMagick's coders in the wrong places. cvcpkg's ImageMagick is extracted, not installed, so Magick has no coders at all (not even xc:) until something points it at them. set_magick_paths_win() tried three places:

    • the directory of cvc.dll;
    • a fixed ..\..\..\..\deps\bin relative to it;
    • CVC_DEPS_PREFIX/CVCPKG_PREFIX.

    In a dev build cvc.dll is in build\bin, while the coders sit beside CORE_RL_MagickCore_.dll in the deps prefix. None of the three matched.

  2. Two code paths skipped that setup entirely.

    • vol_to_slices()/slices_to_volume() use Magick++ directly. So cvc vol2img failed with RegistryKeyLookupFailed CoderModulesPath even after (1) was fixed.
    • ImageTest.ReadsCmykInputAsRgb also uses Magick++ directly, calling a bare InitializeMagick. It passed in a full run, after other cases had initialized Magick, and failed alone. ctest always runs it alone.
  3. cvc_cli_test couldn't find cvc when run directly. Its SetUp() called fs::canonical("/proc/self/exe"), which throws on Windows and macOS. Run without ctest's CVC_CLI_BINARY, every case failed.

What

  • set_magick_paths_win() also tries the directory the ImageMagick DLL was loaded from, found two ways:

    • by name (CORE_RL_MagickCore_.dll, the name in the cvcpkg bundle);
    • by the address of one of its functions, for other builds.

    The existing candidates and the first-with-IM_MOD_RL_*.dll rule are unchanged, and a variable already set in the environment still wins.

  • cvc::init_imagemagick() (new, image.h) exposes the once-only initializer that read_image/write_image already used. It is a no-op without ImageMagick. vol_to_slices(), slices_to_volume() and the CMYK test call it.

  • cvc_cli_test finds cvc/cvc.exe beside itself:

    • GetModuleFileNameW on Windows;
    • _NSGetExecutablePath on macOS;
    • /proc/self/exe on Linux.

    If none works, it skips as it meant to, instead of throwing.

Tests (MSVC 14.38 Release, Windows, no MAGICK_* variables set)

  • image_test 28/28, both in one process and with the CMYK case run alone.
  • cvc_cli_test 173/173 run directly (before: every case failed in SetUp()). Under ctest, Vol2Img/Img2Vol now pass.
  • Full ctest, 4065 cases: everything passes except StateClusterMembership.EventCallbacks, which failed once under -j 8 and passes 5 of 5 alone. That is the heartbeat-timing family noted in state: json, traverse and reset without recursing once per level #668.
  • clang-format 18 is clean.

Found, not fixed

  • cvc hexahedralize --improve crashes now and then with an access violation (0xC0000005). This hit CvcCliTest.Regression_MeshImproveMethodsNoCrash once in five runs and HexahedralizeMethodAndImproveFlags once in a full run. Both pass when repeated. It is unrelated to images.
  • The pycvc ctest entries fail in a dev build tree. _pycvc adds only build\bin as a DLL directory, and Python 3.8+ ignores PATH, so the deps prefix's DLLs are never found. Registering the deps bin makes 20 of 22 scripts pass. (PR CI doesn't build pycvc.)

…very Magick++ use

On Windows the cvcpkg ImageMagick is extracted, not installed, so Magick
has no coders (not even xc:) until MAGICK_CODER_MODULE_PATH and friends
point at them. set_magick_paths_win() looked beside cvc.dll, at a fixed
relative path and under CVC_DEPS_PREFIX/CVCPKG_PREFIX. In a dev build
cvc.dll is in build\bin while the coders sit beside CORE_RL_MagickCore_.dll
in the deps prefix, so none matched and every local run failed with
NoDecodeDelegate unless the environment set the paths (CI does).

- set_magick_paths_win() also tries the directory the ImageMagick DLL was
  loaded from, by name and by the address of one of its functions.
- The once-only initializer is public as cvc::init_imagemagick()
  (image.h). vol_to_slices() and slices_to_volume() call it: they used
  Magick++ directly and never set the paths, so cvc vol2img/img2vol
  failed with RegistryKeyLookupFailed CoderModulesPath. ImageTest's CMYK
  case calls it instead of a bare InitializeMagick, which failed whenever
  that case ran in a process of its own, as ctest runs it.
- cvc_cli_test finds cvc beside itself portably. canonical("/proc/self/exe")
  threw from SetUp() on Windows and macOS whenever CVC_CLI_BINARY was not
  set, failing every case of a direct run.
@transfix
transfix merged commit da936d1 into master Oct 18, 2026
15 checks passed
@transfix
transfix deleted the fix/magick-coders-beside-magickcore branch October 18, 2026 04:25
transfix added a commit that referenced this pull request Oct 24, 2026
… it with no MAGICK_* set (#774)

The cvcpkg ImageMagick is extracted, not installed, so on Windows libcvc
points MAGICK_CODER_MODULE_PATH / MAGICK_FILTER_MODULE_PATH /
MAGICK_CONFIGURE_PATH at the bundle before it initializes Magick.

Setting them from inside the process works. MagickCore 7.1.2 reads them with
GetEnvironmentVariableW each time it opens a module, _putenv_s writes the OS
environment block as well as the CRT's copy, and the bundle's MagickCore has
no DllMain genesis that could run first. The ImageTest/CvcCliTest failures
seen without the variables came from Magick being reached without the
bootstrap, which #673 fixed. What remained:

- The layout guess was dllDir\..\..\..\..\deps\bin, which matches no common
  layout. Try <ancestor>\deps\bin for the first four ancestors of cvc.dll's
  directory instead, so <root>\build-X\bin (or bin\Release) next to
  <root>\deps is found. A build tree whose loaded ImageMagick DLL has no
  coders beside it (CORE_RL_*.dll next to the exe) failed
  ImageTest.ReadsCmykInputAsRgb and CvcCliTest.Vol2ImgExportsSlices /
  Img2VolImportsSlices unless CVC_DEPS_PREFIX was set.
- A deps prefix the environment names now comes before that guess.
- When no directory has coders, nothing is set. Before, the variables were
  pointed at cvc.dll's directory, which also hid the registry paths of an
  ImageMagick that is installed.
- MAGICK_CONFIGURE_PATH is set only to a share\imagemagick that holds the
  config, now also found for a <prefix>\debug\bin.
- A variable counts as already set by the OS environment block, the one
  MagickCore reads, not the CRT's copy.

magick_bootstrap_test is a new executable. It removes the MAGICK_* variables
during static initialization, before anything initializes Magick, then
checks that cvc::init_imagemagick() alone finds the coders and config, and
decodes xc:, PNG and JPEG through Magick++ and TIFF through cvc::image. CI
sets the variables for the whole Windows ctest step, so until now no test
exercised the lookup there.
transfix added a commit that referenced this pull request Oct 26, 2026
The package-windows test step pointed MAGICK_CODER_MODULE_PATH,
MAGICK_FILTER_MODULE_PATH and MAGICK_CONFIGURE_PATH at the deps prefix for
every test. Since #673 and #774 libcvc finds the extracted cvcpkg ImageMagick's
coders and config itself, so the variables only hid that lookup from every test
but magick_bootstrap_test. Without them the whole suite, ImageTest and the
CvcCliTest vol2img/img2vol cases included, runs as a local build does.

The recipe/windows-2022 job never set them: on #774 it passed all 4389 tests,
ImageTest.* and MagickBootstrapTest.* among them. The removed block's
debug\bin branch was dead, since the Windows matrix is Release only.
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