macosimagemagickdylib

How to install ImageMagick portably on macOS when I can't set `DYLD_LIBRARY_PATH`?


I am developing a command line utility for macOS (Mojave) that manipulates images using ImageMagick. I want to share it as a standalone app in such a way that others can use it out-of-the-box without having to install any additional dylibs or frameworks. The Homebrew and MacPorts versions of ImageMagick seem to be "hardwired" to the Mac's system directory structure (/usr/local and /opt/local, respectively) in such a way that it's difficult (impossible?) to put ImageMagick and its delegate libraries into a portable application bundle. So I am instead using the distribution directly from the ImageMagick website.

I followed the installation instructions on that page and put the ImageMagick folder in my home directory (at ~myname). As instructed, I did export DYLD_LIBRARY_PATH="/Users/myname/ImageMagick-7.0.8/lib/". But when I run magick, I get an error message:

$ ~myname/ImageMagick-7.0.8/bin/magick logo: test.jpg
dyld: Library not loaded: /ImageMagick-7.0.8/lib/libMagickCore-7.Q16HDRI.6.dylib
  Referenced from: /Users/myname/ImageMagick-7.0.8/bin/magick
  Reason: image not found
Abort trap: 6
$

Clearly magick isn't finding its dylibs, even when I set DYLD_LIBRARY_PATH as instructed. It appears, in fact, that I can't even export DYLD_LIBRARY_PATH into the environment:

$ export MAGICK_HOME="/Users/myname/ImageMagick-7.0.8"
$ export DYLD_LIBRARY_PATH="$MAGICK_HOME/lib/"
$ echo $DYLD_LIBRARY_PATH
/Users/myname/ImageMagick-7.0.8/lib
$ printenv | grep DYLD_LIBRARY_PATH
   # (nothing)
$ printenv | grep ImageMagick
MAGICK_HOME=/Users/myname/ImageMagick-7.0.8
$ 

What's going on? How can I make ImageMagick portable?


Solution

  • First of all, the version of IM currently on the ImageMagick website (version 7.0.8) is for macOS High Sierra. It's therefore not too surprising that you're having trouble installing it on Mojave. (FWIW, the current Homebrew version (IM 7) and MacPorts (IM 6) do, however, work on Mojave. But, like you, I don't know how to make those versions' handling of the delegates truly portable.)

    The reason you can't export DYLD_LIBRARY_PATH is because of Apple's "System Integrity Protection" (SIP), which it added to newer versions of macOS (El Capitan and later). By default, SIP prohibits doing things like changing the env variable DYLD_LIBRARY_PATH. Although it is possible to disable SIP, Apple does not recommend doing so.

    You can, however, modify magick and its dylibs manually using install_name_tool so that IM 7.0.8 works fine on Mojave. Here's how (in bash):

    # magick: set the correct path to libMagickCore.dylib 
    install_name_tool -change \
        /ImageMagick-7.0.8/lib/libMagickCore-7.Q16HDRI.6.dylib \
        @executable_path/../lib/libMagickCore-7.Q16HDRI.6.dylib \
        /Users/myname/ImageMagick-7.0.8/bin/magick
    
    # magick: set the correct path to libMagickWand.dylib 
    install_name_tool -change \
        /ImageMagick-7.0.8/lib/libMagickWand-7.Q16HDRI.6.dylib \
        @executable_path/../lib/libMagickWand-7.Q16HDRI.6.dylib \
        /Users/myname/ImageMagick-7.0.8/bin/magick
    
    # libMagickWand.dylib: set the correct ID
    install_name_tool -id \
        @executable_path/../lib/libMagickWand-7.Q16HDRI.6.dylib \
        /Users/myname/ImageMagick-7.0.8/lib/libMagickWand-7.Q16HDRI.6.dylib
    
    # libMagickWand.dylib: set the correct path
    install_name_tool -change \
        /ImageMagick-7.0.8/lib/libMagickCore-7.Q16HDRI.6.dylib \
        @executable_path/../lib/libMagickCore-7.Q16HDRI.6.dylib \
        /Users/myname/ImageMagick-7.0.8/lib/libMagickWand-7.Q16HDRI.6.dylib
    
    # libMagickCore.dylib: set the correct ID
    install_name_tool -id \
        @executable_path/../lib/libMagickCore-7.Q16HDRI.6.dylib \
        /Users/myname/ImageMagick-7.0.8/lib/libMagickCore-7.Q16HDRI.6.dylib
    

    Now it works:

    $ /Users/myname/ImageMagick-7.0.8/bin/magick logo: test.jpg
    $ open test.jpg
    $ # (Preview opens a nice picture of the ImageMagick logo.)
    

    This modifies the paths to the dylibs relative to the location of the magick command. As long as you keep the directory structure of the ImageMagick folder intact, it should now be completely portable.

    You can easily put those five install_name_tools commands into a little bash script. I'll leave that as an exercise for the reader. :)