11

I am testing out creating a GUI using the Tkinter module. I was trying to add an image to the GUI using PIL. My code looks like this:

import Tkinter as tk
from PIL import Image, ImageTk

root = tk.Tk()
root.title('background image')

imfile = "foo.png"
im = Image.open(imfile)
im1 = ImageTk.PhotoImage(im)

When I run this code, I come up with some errors that lead to a segfault.

objc[5431]: Class TKApplication is implemented in both/Users/sykeoh/anaconda/lib/libtk8.5.dylib and /System/Library/Frameworks/Tk.framework/Versions/8.5/Tk. One of the two will be used. Which one is undefined.
objc[5431]: Class TKMenu is implemented in both /Users/sykeoh/anaconda/lib/libtk8.5.dylib and /System/Library/Frameworks/Tk.framework/Versions/8.5/Tk. One of the two will be used. Which one is undefined.
objc[5431]: Class TKContentView is implemented in both /Users/sykeoh/anaconda/lib/libtk8.5.dylib and /System/Library/Frameworks/Tk.framework/Versions/8.5/Tk. One of the two will be used. Which one is undefined.
objc[5431]: Class TKWindow is implemented in both /Users/sykeoh/anaconda/lib/libtk8.5.dylib and /System/Library/Frameworks/Tk.framework/Versions/8.5/Tk. One of the two will be used. Which one is undefined.
Segmentation fault: 11

I've looked online and it looks to be an issue with the Tk framework in my Systems library and the other in the anaconda library. However, none of the solutions really seemed to work. Any possible solutions or workarounds?

The issue comes with running ImageTk.Photoimage. If I remove that line of code, there is no issues.

Michael
  • 139
  • 2
  • 5

3 Answers3

9

I know I created the bounty, but I got impatient, decided to investigate, and now I've got something that worked for me. I have a very similar python example to yours, which pretty much does nothing other than try to use Tkinter to display an image passed on the command line, like so:

calebhattingh $ python imageview.py a.jpg
objc[84696]: Class TKApplication is implemented in both /Users/calebhattingh/anaconda/envs/py35/lib/libtk8.5.dylib and /System/Library/Frameworks/Tk.framework/Versions/8.5/Tk. One of the two will be used. Which one is undefined.
objc[84696]: Class TKMenu is implemented in both /Users/calebhattingh/anaconda/envs/py35/lib/libtk8.5.dylib and /System/Library/Frameworks/Tk.framework/Versions/8.5/Tk. One of the two will be used. Which one is undefined.
objc[84696]: Class TKContentView is implemented in both /Users/calebhattingh/anaconda/envs/py35/lib/libtk8.5.dylib and /System/Library/Frameworks/Tk.framework/Versions/8.5/Tk. One of the two will be used. Which one is undefined.
objc[84696]: Class TKWindow is implemented in both /Users/calebhattingh/anaconda/envs/py35/lib/libtk8.5.dylib and /System/Library/Frameworks/Tk.framework/Versions/8.5/Tk. One of the two will be used. Which one is undefined.
Segmentation fault: 11

What's happening is that the binary file, ~/anaconda/envs/py35/lib/python3.5/site-packages/PIL/_imagingtk.so has been linked to a framework, and not the Tcl/Tk libs in the env. You can see this by using otool to see the linking setup:

(py35)  ~/anaconda/envs/py35/lib/python3.5/site-packages/PIL
calebhattingh $ otool -L _imagingtk.so 
_imagingtk.so:
        /System/Library/Frameworks/Tcl.framework/Versions/8.5/Tcl (compatibility version 8.5.0, current version 8.5.9)
        /System/Library/Frameworks/Tk.framework/Versions/8.5/Tk (compatibility version 8.5.0, current version 8.5.9)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)
        /usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)

See those two "framework" lines? With anaconda we don't want that. We want to use the libraries in the env. So let's change them!

First make a backup of your binary (in case you want to revert):

$ cp _imagingtk.so _imagingtk.so.bak

Now run this on the command-line (assuming you are in the same folder as your envname/lib):

$ install_name_tool -change "/System/Library/Frameworks/Tk.framework/Versions/8.5/Tk" "@rpath/libtk8.5.dylib" _imagingtk.so
$ install_name_tool -change "/System/Library/Frameworks/Tcl.framework/Versions/8.5/Tcl" "@rpath/libtcl8.5.dylib" _imagingtk.so

You see that @rpath bit in there? That means whichever one you find on the path. Which works great for anaconda. The linking in the _imagingtk.so library now looks like this:

(py35)  ~/anaconda/envs/py35/lib/python3.5/site-packages/PIL
calebhattingh $ otool -L _imagingtk.so
_imagingtk.so:
        @rpath/libtcl8.5.dylib (compatibility version 8.5.0, current version 8.5.9)
        @rpath/libtk8.5.dylib (compatibility version 8.5.0, current version 8.5.9)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)
        /usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)

After this, your code will run. Someone should probably try to get this upstream.

Addendum: The Tkinter binding in the python distribution, i.e., the currently-active conda env, has the following linking:

  ~/anaconda/envs/py35/lib/python3.5/lib-dynload
calebhattingh $ otool -L _tkinter.cpython-35m-darwin.so 
_tkinter.cpython-35m-darwin.so:
        @loader_path/../../libtcl8.5.dylib (compatibility version 8.5.0, current version 8.5.18)
        @loader_path/../../libtk8.5.dylib (compatibility version 8.5.0, current version 8.5.18)
        /usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 111.0.0)

If you prefer, you can rather use install_name_tool to use @loader_path/../../ instead of what I used above, i.e. @rpath/. That will probably also work, and might even be better.

Caleb Hattingh
  • 9,005
  • 2
  • 31
  • 44
  • 1
    It's worked for me, thanks! Also, you can find binaries, that linked to system Tkinter by simple commands: `grep -rnw 'Tk.framework ' ` and `grep -rnw 'Tcl.framework ' ` – lucidyan May 20 '16 at 20:06
  • Thanks so much for this. So is this a bug in Conda? – Gus Apr 06 '17 at 15:32
  • No, I think it's to do with Pillow. If the package was a conda package, then the bug is that that pkg wasn't built correctly. If the package was pip-installed (I can't remember), then the bug was me expecting that a non-conda package being installed into a conda environment would work ;) – Caleb Hattingh Apr 09 '17 at 05:06
2

I try to conduct my own investigation of this problem (in my case that was problem with matplotlib)

  • I try to found binaries, linked with System Tcl/Tk Library paths
  • With libraries i found file, which seems really interesting. It has name name osx-tk.patch and was placed in ~/anaconda/pkgs/matplotlib-1.5.1-np111py35_0/info/recipe/
  • Found osx-tk.patch sources into GitHub

  • After reading the patch and Conda documentation i became finally convinced about wrong package installation, and i remember, that i used pip for matplotlib installation!

  • I deleted old package with pip and install new one with conda install matplotlib command

  • Now everything started to work like a charm!

Brief summary:

Using pip package manager with conda environment, i messed my dependencies, because conda may using special recipes, that point installer how to install package correctly in conda virtual environment

Ultra-Brief summary:

Delete package fully with dependencies and install it again with conda package manager (use rebinding only in difficult cases)

lucidyan
  • 3,575
  • 2
  • 22
  • 24
  • This is a very interesting point I hadn't considered. I'm fairly sure that I install Pillow through conda though, but it's still worth considering for other situations where packages are installed into the same env with both conda and pip. – Caleb Hattingh May 21 '16 at 01:41
1

I did exactly what @cjrh said for _imagetk.so, but instead for _tkinter.so in ~/anaconda/lib/python3.5/lib-dynload/ and it worked great!

cd ~/anaconda/lib/python3.5/lib-dynload

$ install_name_tool -change "/System/Library/Frameworks/Tk.framework/Versions/8.5/Tk" "@rpath/libtk8.5.dylib" _tkinter.so
$ install_name_tool -change "/System/Library/Frameworks/Tcl.framework/Versions/8.5/Tcl" "@rpath/libtcl8.5.dylib" _tkinter.so
gabra
  • 9,484
  • 4
  • 29
  • 45