Skip to content

image: find ImageMagick's coders beside a build tree on Windows; test with no MAGICK_* set - #774

Merged
transfix merged 2 commits into
masterfrom
fix/magick-windows-bootstrap
Oct 24, 2026
Merged

transfix merged 2 commits into
masterfrom
fix/magick-windows-bootstrap

Conversation

@transfix

Copy link
Copy Markdown
Owner

On Windows the cvcpkg ImageMagick is extracted, not installed, so it has no registry entry. libcvc points MAGICK_CODER_MODULE_PATH / MAGICK_FILTER_MODULE_PATH / MAGICK_CONFIGURE_PATH at the bundle before it initializes Magick (set_magick_paths_win() in src/cvc/image/magick_io.cpp). This PR fixes the layout lookup that remained broken and adds a test that runs with none of those variables set.

What was actually wrong

Three suspects were open: a different CRT inside ImageMagick, the bootstrap running after genesis had cached the path, and the bootstrap never being reached. A standalone exe linked against the same deps ImageMagick (7.1.2) ruled out the first two:

  • MagickCore imports GetEnvironmentVariableW and no CRT getenv, so it reads the OS environment block. _putenv_s writes that block as well as the CRT's copy. The exe saw the variables, and Magick decoded xc: and PNG after an in-process _putenv_s.
  • The module path is read each time a module is opened, not cached. Setting the variables even after a failed xc: lookup fixes the next lookup.
  • IsMagickCoreInstantiated() is false at main, so the bundle has no DllMain genesis that could run before libcvc.

The failures seen on 2026-10-09 came from the third suspect: Magick was reached without the bootstrap. #673 has since fixed that, and it also tries the directory of the loaded CORE_RL_MagickCore_.dll. What remained:

  • The layout guess dllDir\..\..\..\..\deps\bin matches no common layout. This PR tries <ancestor>\deps\bin for the first four ancestors of cvc.dll's directory instead, which finds <root>\deps next to <root>\build-X\bin (or bin\Release). A deps prefix named in the environment (CVC_DEPS_PREFIX / LIBCVC_DEPS_PREFIX / CVCPKG_PREFIX) now comes before this guess.
  • When no directory has coders, nothing is set. Before, the variables were pointed at cvc.dll's directory, which has no coders. That also hid the registry paths of an ImageMagick that is installed.
  • MAGICK_CONFIGURE_PATH is set only to a share\imagemagick that holds .xml config. The lookup also covers a <prefix>\debug\bin layout (<prefix>\share\imagemagick), which CI's Debug lane uses.
  • "Already set" is now checked against the OS environment block, the one MagickCore reads, instead of the CRT's copy. A user's override still wins.

New test: magick_bootstrap_test

This is a separate executable, because the bootstrap runs once per process. During static initialization, before anything can initialize Magick, it removes the three MAGICK_* variables and records whether Magick was already up. Then:

  • ReadsXcWithoutMagickEnvironment (all platforms): cvc::init_imagemagick() alone makes xc: work.
  • PointsMagickAtTheCoderModules (Windows): the variables it set name a directory with IM_MOD_RL_png_.dll and a config directory with .xml files.
  • RoundTripsPngAndJpegWithoutMagickEnvironment (Windows): PNG and JPEG are written and read back through Magick++ directly. cvc::image reads both with stb first, so it can't prove that Magick's own decoders load.
  • CvcImageRoundTripsTiffWithoutMagickEnvironment (Windows): TIFF goes through cvc::image, which has no stb path for TIFF in either direction.

CI sets the MAGICK_* variables for the whole Windows ctest step, so until now no test exercised the lookup there. This PR leaves that CI step alone.

Verification (Windows, MSVC 14.44, Release, shared, ImageMagick ON)

Build tree C:\Users\tfx\src\cvc\build-magickboot, a sibling of the deps prefix. Every run has no MAGICK_* and no CVC_DEPS_PREFIX unless the layout says so. The runs are image_test (all 28 tests), cvc_cli_test --gtest_filter=*Vol2Img*:*Img2Vol* and magick_bootstrap_test.

Layout master (82a3901) this PR
A: build\bin + deps\bin on PATH (normal dev run) pass pass
B: A with CORE_RL_*.dll copied into build\bin, so the loaded ImageMagick has no coders beside it fails: ImageTest.ReadsCmykInputAsRgb, both CvcCli cases, all 4 new tests (NoDecodeDelegate xc:, MAGICK_CODER_MODULE_PATH=...\build-magickboot\bin) pass
C: B + CVC_DEPS_PREFIX pass pass
D: A + the MAGICK_* values CI sets pass pass

ctest -R "MagickBootstrapTest|ImageTest|CvcCliTest.(Vol2Img|Img2Vol)", with no variables set and one process per case: 34/34 passed. Linux and macOS weren't built locally. On those platforms the new executable only runs the xc: case, which ImageTest.ReadsCmykInputAsRgb already does unguarded.

… it with no MAGICK_* set

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
transfix merged commit 5f994bd into master Oct 24, 2026
24 checks passed
@transfix
transfix deleted the fix/magick-windows-bootstrap branch October 24, 2026 15:40
transfix added a commit that referenced this pull request Oct 24, 2026
Carries the master merge (#776 squash, #774, #775, #777, #780, #782,
#784, #785) up the H1 stack.
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