Проблема двойной реализации TK Framework

Я тестирую создание графического интерфейса с помощью модуля Tkinter. Я пытался добавить изображение в графический интерфейс с помощью PIL. Мой код выглядит следующим образом:

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)

Когда я запускаю этот код, я придумываю некоторые ошибки, которые приводят к 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

Я посмотрел онлайн и, похоже, проблема с базой Tk в моей библиотеке Systems, а другая в библиотеке anaconda. Однако ни одно из решений действительно не сработало. Любые возможные решения или обходные пути?

Проблема связана с запуском ImageTk.Photoimage. Если я удалю эту строку кода, проблем нет.

Ответ 1

Я знаю, что я создал щедрость, но я был нетерпелив, решил исследовать, и теперь у меня есть кое-что, что сработало для меня. У меня очень похожий пример python для вашего, что почти ничего не значит, кроме попытки использовать Tkinter для отображения изображения, переданного в командной строке, например:

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

Что происходит, так это то, что двоичный файл ~/anaconda/envs/py35/lib/python3.5/site-packages/PIL/_imagingtk.so связан с каркасом, а не с Tcl/Tk libs в env. Вы можете увидеть это, используя otool, чтобы увидеть настройку компоновки:

(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)

Посмотрите на эти две строки "рамки"? С анакондой мы этого не хотим. Мы хотим использовать библиотеки в env. Так что дайте им изменения!

Сначала создайте резервную копию своего двоичного файла (в случае, если вы хотите вернуться):

$ cp _imagingtk.so _imagingtk.so.bak

Теперь запустите это в командной строке (если вы находитесь в той же папке, что и ваш 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

Вы видите бит @rpath? Это означает, что вы найдете на пути. Что отлично работает для анаконды. Связывание в библиотеке _imagingtk.so теперь выглядит следующим образом:

(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)

После этого ваш код будет запущен. Кто-то должен, вероятно, попытаться получить это вверх по течению.

Добавление: привязка Tkinter в дистрибутиве python, то есть текущая активная conda env, имеет следующую ссылку:

🎨  ~/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)

Если вы предпочитаете, вы можете использовать install_name_tool для использования @loader_path/../../ вместо того, что я использовал выше, т.е. @rpath/. Это, вероятно, также будет работать, и может быть даже лучше.

Ответ 2

Я пытаюсь провести собственное исследование этой проблемы (в моем случае это проблема с matplotlib)

  • Я пытаюсь найти двоичные файлы, связанные с путями System Tcl/Tk Library
  • В библиотеках я нашел файл, который кажется действительно интересным. Он имеет имя osx-tk.patch и помещен в ~/anaconda/pkgs/matplotlib-1.5.1-np111py35_0/info/recipe/
  • Найденные osx-tk.patch источники в GitHub

  • После прочтения патча и документации по Conda я наконец убедился в неправильной установке пакета, и я помните, что я использовал pip для установки matplotlib!

  • Я удалил старый пакет с pip и установил новый с помощью команды conda install matplotlib

  • Теперь все стало работать как шарм!

Краткое резюме:

Используя pip менеджер пакетов с средой conda, я испортил свои зависимости, потому что conda может использовать специальный recipes, этот установщик точки, как правильно установить пакет в виртуальной среде conda

Ультра-краткий обзор:

Удалить пакет полностью с зависимостями и снова установить его с помощью диспетчера пакетов conda (используйте переупорядочивание только в трудных случаях)

Ответ 3

Я сделал именно то, что @cjrh сказал для _imagetk.so, но вместо этого для _tkinter.so в ~/anaconda/lib/python3.5/lib-dynload/, и он отлично работает!

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