Is it possible to compile a static/portable version of ImageMagick for High Sierra/Mojave?

Viewed 1162

This question was already asked, 4 years ago, so the High Sierra/Mojave part are new. Here is the link to the unanswered question: compile static version of imagemagick convert util

I am trying to compile portable version of IM that I can include with a script that could be used on other MacOS machines, without the need for developer tools or Mac Ports to first be installed on the machine. I see that ImageMagick.org provide static and portable builds for Windows, but only provide a precompiled binary for OS X/Darwin.

When I try to run the precompiled version on a Mac with a fresh install of Mojave I get the following:

dyld: Library not loaded: /ImageMagick-7.0.8/lib/libMagickCore-7.Q16HDRI.6.dylib
  Referenced from: /Users/chrisnorman/Desktop/ImageMagick-7.0.8/bin/./magick
  Reason: image not found

When I run otool (which required that I install the command line developer tools) against the precompiled binary ot magick I get the following:

otool -L magick
magick:
    /ImageMagick-7.0.8/lib/libMagickCore-7.Q16HDRI.6.dylib (compatibility version 7.0.0, current version 7.0.0)
    /ImageMagick-7.0.8/lib/libMagickWand-7.Q16HDRI.6.dylib (compatibility version 7.0.0, current version 7.0.0)
    /usr/lib/libbz2.1.0.dylib (compatibility version 1.0.0, current version 1.0.5)
    /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.0.0)
    /usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0)

which is a shorter list than I had gotten when I was trying to use a binary that I had compiled on another Mac and run on the fresh install of Mojave Mac.

I would just like some guidance on how to compile a version similar to the portable version of IM that they have precompiled for Windows on the ImageMagick downloads page. Something I can just throw on any Mac and run it without needing to worry about if a bunch of dynamic libraries are already installed on the machine.

Here is my current installation script for trying to build IM on a Mac that already has Xcode on it:

#!/bin/bash

set -e

IMBUILD=/tmp/imbuild/
mkdir -p $IMBUILD/bin

# get IM (Version 7 at the moment)
mkdir im_download && cd im_download
curl -O http://www.imagemagick.org/download/ImageMagick.tar.gz
for file in *.gz ; do tar zxf $file; done
rm *.tar.gz
cd ImageM*

# get delegates
# jpeg
echo ">>>>>>>>>>>>>> JPEG"
curl -O http://www.imagemagick.org/download/delegates/jpegsrc.v9b.tar.gz
tar zxf jpeg*.gz && rm jpeg*.gz && mv jpeg* jpeg && cd jpeg
./configure --disable-shared --disable-dependency-tracking
make
cd ..

# png
echo ">>>>>>>>>>>>>> PNG"
curl -O http://www.imagemagick.org/download/delegates/libpng-1.6.31.tar.gz
tar zxf libpng*.gz && rm libpng*.gz && mv libpng* png && cd png
./configure --disable-shared --disable-dependency-tracking
make
cd ..

# lcms
echo ">>>>>>>>>>>>>> LCMS"
curl -O http://www.imagemagick.org/download/delegates/lcms2-2.8.tar.gz
tar zxf lcms2*.gz && rm lcms2*.gz && mv lcms2* lcms && cd lcms
./configure --disable-shared --disable-dependency-tracking
make
cd ..

# tiff
echo ">>>>>>>>>>>>>> TIFF"
curl -O http://www.imagemagick.org/download/delegates/tiff-4.0.8.tar.gz
tar zxf tiff*.gz && rm tiff*.gz && mv tiff* tiff && cd tiff
./configure --disable-shared --disable-dependency-tracking
make
cd ..

#build imagemagick (YMMV)
echo ">>>>>>>>>>>>>> IMAGEMAGICK"
./configure --disable-shared \
    --disable-dependency-tracking \
    --disable-shared \
    --enable-osx-universal-build \
    --enable-delegate-build \
    --enable-static \
    --disable-installed \
    --without-frozenpaths \
    --prefix=$IMBUILD \
    --with-openexr=no \
    --disable-docs \
    --with-lcms=yes \
    --without-x \
    --without-webp \
    --without-modules \
    --with-zero-configuration \
    --with-jpeg \
    --without-pango \
    --enable-hdri=no \
    --without-gvc \
    --with-raw

make install

ls $IMBUILD/bin

The configuration above is what I am going for, so what I need most are JPEG, TIFF and LCMS.

So any pointers or tips on what I need to add to this script to get a truly portable version of IM would be fantastic!

1 Answers

I am no expert on this, but I read somewhere that the Apple linker always prefers dynamic libraries over static ones, i.e. it chooses libraries ending in .dylib in preference to libraries ending in .a.

So, I copied your shell script and edited it to build ImageMagick with very few options enabled in order to reduce the configure/build time. Then I dinked around with the options.

I have not done any exhaustive testing and don't have a spare clean Mac lying around without my beloved ImageMagick on it. However, I built ImageMagick and checked the dependencies with:

otool -L ./magick

./magick:
    /usr/local/opt/libpng/lib/libpng16.16.dylib (compatibility version 54.0.0, current version 54.0.0)
    /usr/local/opt/fftw/lib/libfftw3.3.dylib (compatibility version 9.0.0, current version 9.8.0)
    /usr/local/opt/fontconfig/lib/libfontconfig.1.dylib (compatibility version 14.0.0, current version 14.0.0)
    /usr/local/opt/freetype/lib/libfreetype.6.dylib (compatibility version 24.0.0, current version 24.0.0)
    /usr/local/opt/xz/lib/liblzma.5.dylib (compatibility version 8.0.0, current version 8.4.0)
    /usr/lib/libbz2.1.0.dylib (compatibility version 1.0.0, current version 1.0.5)
    /usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.11)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.250.1)

I then discovered that if I temporarily rename the libpng dynamic library and rebuild (after using make distclean), then the dependency disappears.

I assume (guess/hope) therefore that if you deleted (or maybe preferably renamed) the dynamic libraries in all your delegates, it would link statically and you might get something redstributable.

As an example, here's how I forced libjpeg to link statically. As mine is installed via homebrew, I find the dynamic library like this:

brew ls --verbose jpeg | grep dylib

And that tells me it is here:

/usr/local/Cellar/jpeg/9c/lib/libjpeg.dylib

So, I go there and hide that from the linker:

cd /usr/local/Cellar/jpeg/9c/lib
mv libjpeg.dylib HIDDENlibjpeg.dylibHIDDEN

Here's the script I was using:

#!/bin/bash
################################################################################
# macBuildPortableMagick
# Mark Setchell
#
# Build PORTABLE ImageMagick from source and install under my user without 
# clashing with any system derived packages.
################################################################################
INSTALLDIR=$HOME/ImageMagick
BUILDDIR=$HOME/ImageMagick/ImageMagick

# Create the installation directory
mkdir -p "$INSTALLDIR"

# Go to the distribution, clean, build and install
cd "$BUILDDIR"
if [ $? -ne 0 ] ; then 
   >&2 echo ERROR: Unable to change directory to $BUILDDIR
   exit 1
fi

make distclean

./configure \
   CC=clang \
   CFLAGS="-O3" \
   CXX=clang++ \
   CXXFLAGS="-std=c++11 -O3 -march=native"  \
   --disable-dependency-tracking \
   --without-x \
   --without-magick-plus-plus \
   --disable-shared \
   --enable-static \
   --with-quantum-depth=16 \
   --enable-hdri=no \
   --prefix="$INSTALLDIR" \
   --disable-docs \
   --disable-osx-universal-binary \
   --disable-silent-rules \
   --enable-zero-configuration \
   --with-jpeg \
   --with-heic=no \
   --with-lcms=no \
   --with-openexr=no \
   --with-openjp2=no \
   --with-tiff=no \
   --with-xml=no \
   --with-webp=no

# I prefer to check things before copying and pasting the next bit
exit
make -j 8 && make install

If anyone knows more about this and can add some insights - please let me know via comments or by editing and adding a new paragraph at the end of the answer.

Related