3

I'm trying to deploy ImageMagick with my own software. On windows I've just included all the core dlls with coders dlls at the exe path and it works well. But on mac os I have troubles with coders. I installed ImageMagick via macports and found it with the help of CMake. CMake does all the job of copying and fixing up all the core libs I've linked against. Then I copied all the coder libs and fixed them up also, but when I start my application it just can't find any coder. So I'd like to know what am I missing there.

Note: if I didn't fix up any paths it works well. It is only my deployment that is in trouble. Maybe I should include some kind of config file?

P.S. I have all ImageMagick libs including coders SOs near the executable in MacOS bundle sub-folder.

ixSci
  • 13,100
  • 5
  • 45
  • 79

3 Answers3

4

How about setting the MAGICK_CODER_MODULE_PATH in your bundle?

see here: http://www.imagemagick.org/script/resources.php

EDIT:

To improve the information:

Originally when embedding IM in our own app bundle we had three problems:

  1. our app and the IM dylibs not finding referenced IM dylibs,
  2. IM not finding its config files,
  3. IM not finding coders (the No Decode Delegate error)

We tried changing the hardcoded paths in the dylibs using the install_name_tool but finally when doing some tests with moving the IM around to different directories and testing

convert -debug configuration 

we found out the all three above problems could be solved just by setting and exporting at least these three environment variables in the terminal console before running convert:

DYLD_LIBRARY_PATH
MAGICK_CONFIGURE_PATH
MAGICK_CODER_MODULE_PATH

With this experience, we returned back to our bundle and in the beginning tried to use the Info.plist fiel to set these variables but it didn't seem to work - probably because there were problems with making the paths to IM inside the bundle relative.

Finally we created a simple sh script and put it into our bundle and configured this bundle to run this script instead of the main app:

#!/bin/sh
CURR_DIR="$( cd -P "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
IMAGE_MAGICK_PATH=$CURR_DIR/../Resources/ImageMagick

export DYLD_LIBRARY_PATH=$IMAGE_MAGICK_PATH/lib
export MAGICK_CONFIGURE_PATH=$IMAGE_MAGICK_PATH/lib/ImageMagick-6.8.0/config
export MAGICK_CODER_MODULE_PATH=$IMAGE_MAGICK_PATH/lib/ImageMagick-6.8.0/modules-Q16/coders

# run application
exec $CURR_DIR/OurAppName

The key thing to make it working was properly getting the CURR_DIR of the app bundle (thanks to this post).

And as came out of our tests, setting the environment variables this way makes them visible only for this application execution context - i.e. when we started our app using the bundle, opened terminal and typed

env

the above three variables were missing from the output.

Hope this will help others save couple of days of research and pulling hairs out of their heads ;)

Community
  • 1
  • 1
Tomasz
  • 151
  • 5
  • Why just partly? Telling the truth my team is exectly right now working on creating the app bundle with IM embedded and we also have problems. Setting the MAGICK_CODER_MODULE_PATH solved the NoDecodeDelagate errors when we were doing tests with moving around the IM libraries... So where are you now, maybe we can work things out together if we are in the similar stage ;) – Tomasz Apr 24 '13 at 09:35
  • For me it requires to clear two fields in .la which contains paths. After setting MAGICK_CODER_MODULE_PATH and clearing those fields it starts working. It is why I've said that it helps partly. – ixSci Apr 24 '13 at 10:37
  • [Another](http://stackoverflow.com/questions/16184505/set-environment-variable-for-the-process-before-startup) issue appears with using MAGICK_CODER_MODULE_PATH – ixSci Apr 24 '13 at 10:39
  • which issue - a need to call lsregister? I think this is only required if you change it, when the app is run first time, there should be no issue... or you are having some other problem? – Tomasz Apr 24 '13 at 11:10
  • Does LSEnvironment work for you? Because for me it didn't but I didn't know about caching. – ixSci Apr 24 '13 at 11:21
  • well, ok we've finally found a solution: first of all we create the bundle manually, then we just use the sh script to set all three environment variables (DYLD_LIBRARY_PATH, MAGICK_CODER_MODULE_PATH and MAGICK_CONFIGURE_PATH) do the dirs inside the bundle. There is one important thing though - you have to get the current full dir when setting those. And we just put the IM binary distribution into our bundle and everything works. Telling the truth it took us two days of research, but finally it works. Let me know if you need more detialed description. – Tomasz Apr 24 '13 at 12:08
  • Alas, sh script for setting up MAGICK_CODER_MODULE_PATH variable system wide is not an option for me. Anyone can change it and application will be broken. And by setting it on an end user machine you have a chance that you will break some other user software(e.g. ImageMagick itself) – ixSci Apr 24 '13 at 12:15
  • the sh script inside the bundle does not change it system wide AFAIK - only for the given execution context - am I mistaken? EDIT: have just checked - these variables are not visible to the system - as I said only for the given app execution context. – Tomasz Apr 24 '13 at 12:16
  • I've tried solution with script and it didn't work for me either(it still run the main executable and ignored script). I think I was beaten by the Info.plist caching again. So I will try both solutions tomorrow. I grant you the bounty since you have posted at least one solution which works for you. But I will accept it as the answer(or not) only after I have working solution for me. – ixSci Apr 24 '13 at 15:16
  • ixSci, thanks for the bounties! I'm available to help you. We can have a chat some time tomorrow during the day and I can try to help you debugging your problem. I'll be checking for you answer here tomorrow. – Tomasz Apr 24 '13 at 17:35
2

I've found a full solution for deploying ImageMagick in a bundle with the help of CMake. If you don't use CMake then @Tomasz's answer will be of help also. So let's start:

First of all you need to know what and where ImageMagick is trying to locate when it is used from your own code. To find it out you can use MAGICK_DEBUG environmental variable which could be set to those parameters. It really helps when you debug ImageMagick.

Prerequisites: I assume that you used FIND_PACKAGE and FIXUP_BUNDLE to find ImageMagick and set its binary paths inside the bundle. The only thing left is to deploy coders. Also I assume that you've installed ImageMagick from Mac Ports.

  1. We need to get ImageMagick version string to correctly locate the coders:

    STRING(REGEX REPLACE "-.+" "" ImageMagick_SHORT_VERSION ${ImageMagick_VERSION_STRING})
    

    Now ImageMagick_SHORT_VERSION contains full version without any sub versions.

  2. Then we need to copy all the coders to some predefined folder(I've used ImageMagick/coders subfolder under MacOS part of the bundle)

    FILE(COPY /opt/local/lib/ImageMagick-${ImageMagick_SHORT_VERSION}/modules-Q16/coders/ DESTINATION ${PATH_TO_YOUR_BUNDLE}/Contents/MacOS/ImageMagick/coders/)
    
  3. Now we need to fixup all the *.so libs we have, so we list it and pass to fixup_bundle

    FILE(GLOB IMAGEMAGICK_CODERS ${PATH_TO_YOUR_BUNDLE}/Contents/MacOS/ImageMagick/coders/*.so)
    
  4. Now we should update *.la files which accompanies coders *.so. To achieve it I've used script:

    INSTALL(SCRIPT LaScript.cmake COMPONENT Runtime)
    

Script content:

SET(TARGET_BINARY_DIR "${PATH_TO_YOUR_BUNDLE}")
FILE(GLOB IMAGEMAGICK_CODERS_LA ${TARGET_BINARY_DIR}/Contents/MacOS/ImageMagick/coders/*.la)
FOREACH(file ${IMAGEMAGICK_CODERS_LA})
    FILE(READ ${file} FILE_CONTENT)
    STRING(REGEX REPLACE "dependency_libs='.*'" " " MODIFIED_FILE_CONTENT ${FILE_CONTENT})
    STRING(REGEX REPLACE "libdir='.*'" " " MODIFIED_FILE_CONTENT ${MODIFIED_FILE_CONTENT})
    FILE(WRITE ${file} ${MODIFIED_FILE_CONTENT})
ENDFOREACH()

We almost ready the only thing left to be done is to change the way we launch the application. But let's digress a little bit and find out where ImageMagick searches for the coders:

  • It tries to get the content of MAGICK_CODER_MODULE_PATH environmental variable
  • Then it checks if MAGICKCORE_CODER_PATH macro is defined(and in fact it does!) and use its value.

Then it will try to use MAGICK_HOME environmental variable and MAGICKCORE_CODER_RELATIVE_PATH to get path to the modules but we don't care since we will stop on #2 anyway!(NOTE: that it is true for Mac Ports installation)

So the only way we can interfere with search is to set MAGICK_CODER_MODULE_PATH environmental variable(Well we can also edit libMagickCodre and replace MAGICKCORE_CODER_PATH with some static path we need but it is too britle way to do things and it won't save us if someone set MAGICK_CODER_MODULE_PATH anyway) We shouldn't set it system wide since we can break some user installtion so we have 2 options:

  • Use LSEnvironment to set the MAGICK_CODER_MODULE_PATH to some predefined location
  • Use script to launch our app and set this variable inside it.

I've chose the later since it is more flexible, I have the following script:

#!/bin/bash
working_dir="${0%/*}"
export MAGICK_CODER_MODULE_PATH=$working_dir/ImageMagick/coders
executable="${working_dir}/ApplicationName"
"$executable"

and set CFBundleExecutable to the name of the script.

That's all and I hope it will help someone to save his/her time.

ixSci
  • 13,100
  • 5
  • 45
  • 79
1

You should follow the Mac OS X-specific Build instructions but specifying --enable-shared in the configure options (see this document for details).

I guess that your application can't find the codecs because they have been statically linked to ImageMagick tools. This is usually done to address portability issues. To make codecs available in your application, you should build them as shared objects.

Giacomo Tesio
  • 7,144
  • 3
  • 31
  • 48
  • 1
    while your answer is valuable it answers absolutely different question. I didn't ask "how to build ImageMagick under MAC OS" – ixSci Apr 24 '13 at 07:27
  • @ixSci I guess that your application can't find the codecs because they have been statically linked to ImageMagick tools. This is usually done to address portability issues. To make codecs available in your application, you should build them as shared objects. Thus you need --enable-chared. – Giacomo Tesio Apr 24 '13 at 07:31
  • No, issue is different. I have a right direction but I'm still struggling to solve it. I will post my solution when it will be solved. – ixSci Apr 24 '13 at 07:35