nlfiedler / magick-rust

Rust bindings for ImageMagick
https://crates.io/crates/magick_rust
Apache License 2.0
259 stars 68 forks source link

Improve build/install instructions for Windows #124

Open nlfiedler opened 5 months ago

nlfiedler commented 5 months ago

The existing instructions are not adequate to build this crate on Windows. I will soon submit a change that helps, but still isn't completely satisfying because one of the bindings unit tests fails (size of long double). I'm hoping someone like @gyk can offer some insight. Questions I have:

  1. Assuming the use of MSYS2, how to get clang such that the unit tests pass? I see the github action for testing on Windows, but I don't get how everything is set up (where is clang?).
  2. Is it necessary to set IMAGE_MAGICK_INCLUDE_DIRS to include the path to mm_malloc.h because without that, the build fails to find that header file. This is unlike on other platforms, which is why I wonder if I'm doing something wrong.
  3. I added instructions using MSYS2 to the INSTALL.md file, if those need fixing, please let me know.

Hoping someone who knows Windows better than I (who only really uses it for video games) can help.

Other concerns I have: can we possibly build this crate on Windows without introducing a Unix-like environment? For instance, using the Visual Studio Installer should suffice, but it installs a 32-bit version of Clang, which is like WTF. Hard to image how people use Windows for anything other than C# development.

5ohue commented 5 months ago

That would be very handy!

5ohue commented 5 months ago

The MSYS instructions worked! What a timing, just as I started to try to compile it on windows and have issues, you added the instructions. Thanks!

gyk commented 5 months ago

Hi,

  1. In #114 I chose mingw64 environment, but we should switch to ucrt64 as it causes fewer compatibility issues. Please see this commit. Most unit tests in v0.19 except test_set_background_color will pass.

    one of the bindings unit tests fails (size of long double)

    Which one is it?

    Regarding to clang, LLVM is preinstalled in the GitHub Actions runner image so it is already usable.

  2. Never come across any problems related to mm_malloc.h.


can we possibly build this crate on Windows without introducing a Unix-like environment?

Of course we can. I believe MSYS2 support was added to address this use case: Some application needs to be released on multiple platforms, and may require a custom build of ImageMagick. Unfortunately ImageMagick uses separate instructions to build natively on Windows and it looks complicated, in this case, using MSYS2 is preferable.

gyk commented 5 months ago

The following may be helpful for someone trying to build this crate against MSYS2.

As other Unix-like environments, there are two approaches for MSYS2:

  1. Set up everything manually:

    $env:PATH = "C:\msys64\usr\bin;C:\msys64\ucrt64\bin;$env:Path"
    $env:IMAGE_MAGICK_DIR = "C:\msys64\ucrt64"
    $env:IMAGE_MAGICK_INCLUDE_DIRS = "C:\msys64\ucrt64\include\ImageMagick-7"
    $env:IMAGE_MAGICK_LIB_DIRS = "C:\msys64\ucrt64\lib"
    $env:IMAGE_MAGICK_LIBS = "libMagickCore-7.Q16.dll.a;libMagickWand-7.Q16.dll.a"
  2. Just rely on pkg-config to resolve the configuration:

    $env:PATH = "C:\msys64\usr\bin;C:\msys64\ucrt64\bin;$env:Path"
    $env:IMAGE_MAGICK_LIBS = "libMagickCore-7.Q16.dll.a;libMagickWand-7.Q16.dll.a"

Please note that the order in $env:PATH is important. C:\msys64\usr\bin appears first to make sure MSYS2's sh takes precedence over other sh.exe installed in the system. C:\msys64\ucrt64\bin introduces essential commands like pkg-config and MagickCore-config.

5ohue commented 5 months ago

Also, after I built a rust project with this library, it works fine when its run from the MSYS2 MINGW64 shell. But running a compiled executable directly without the mingw64 envirenment (just running it from CMD.exe for example) causes NoDecodeDelegateForThisImageFormat 'PNG' @ error/constitute.c/ReadImage/746 error to appear. That makes me think image magick maybe relies on some env variables to find the libraries. Not sure what I could do.

Maybe something about shipping the executable on windows should be added to INSTALL.md, since you cannot just ask users to "sudo apt install libeverthing-thats-needed", windows has a funny way of installing software :) and just putting all dlls in the same folder as the .exe doesn't seem to work (it gives errors like the one I have with PNGs not opening)

gyk commented 5 months ago

@5ohue The env variable is MAGICK_CODER_MODULE_PATH. Without it ImageMagick will try to read coder path from the registry. However, if you're willing to build ImageMagick from scratch, coder modules can be disabled by passing --without-modules to configure.

5ohue commented 5 months ago

@nlfiedler I think I found a way to compile, run and destribute an application that uses magick-rust. It requires using MSYS2 to compile, but the final executable doesn't require users to install anything additional. Here's how it worked for me:

  1. I installed MSYS2 and the needed packages. Unfortunately I don't currently have a nice list of packages. I used MINGW64 packages instead of UCRT64 (the latter doesn't work for some reason). So I installed packages like mingw-w64-x86_64-imagemagick, mingw-w64-x86_64-rust and probably some more. I can try to get a nice list of packages later.
  2. I opened powershell and ran these commands (thank a lot @gyk!):
    $env:PATH = "C:\msys64\usr\bin;C:\msys64\mingw64\bin;$env:Path"
    $env:IMAGE_MAGICK_DIR = "C:\msys64\mingw64"
    $env:IMAGE_MAGICK_INCLUDE_DIRS = "C:\msys64\mingw64\include\ImageMagick-7"
    $env:IMAGE_MAGICK_LIB_DIRS = "C:\msys64\mingw64\lib"
    $env:IMAGE_MAGICK_LIBS = "libMagickCore-7.Q16HDRI.dll.a;libMagickWand-7.Q16HDRI.dll.a"
  3. I cded into the crate's directory and built the project (cargo build --release or cargo install --path . or any other way to build a crate). It compiles fine here for me.
  4. I copied all the dynamic libraries the executable is linked to. I did that by running this command from inside of MSYS2 shell: ldd <PATH TO EXECUTABLE>.exe | awk '{print ($3)}' | grep "^/mingw64" | xargs -I FILE cp FILE lib/. The lib folder now contains all the DLL files.
  5. I created the app folder. The folder structure is this:
    <APP NAME>\
    bin\
        *.dll
        <EXECUTABLE>.exe
    lib\
        ImageMagick-7.1.1\

    So basically I copied all the DLL files and executable to bin\ folder (and also some additional DLLs for extra file formats, like libjpeg-8.dll file for example. The application isn't directly linked to that, so ldd cannot know about it). To bin\ folder I copied the ImageMagick-7.1.1 folder from C:\msys64\mingw64\lib.

  6. Now opening powershell and running the executable works without having to tinker with path or anything else. The <APP NAME> can now be packaged and shared to other computers, and the executable can be run without problems.
RivenSkaye commented 2 weeks ago

Using The Windows-specific repo for ImageMagick and going through the process to see the eventual build scripts may help us get to a static lib. That'd solve most if not all of the issues here I think?