Python3 Ошибка типа CTypes при загрузке dylib в Ма c 10.14 (Мохаве) - PullRequest
0 голосов
/ 08 февраля 2020

Справочная информация

Я прочитал бесчисленные темы проекта GitHub и все, что я могу найти в StackOverflow об этой проблеме, хотя пока что не повезло. У меня есть окно Ma c 10.14, работающее со стандартными CommandLineTools и / или Xcode. Я пытаюсь "портировать" библиотеку-оболочку Python, которую я написал, вокруг старой библиотеки C и C ++ с использованием CTypes в Python3. Хорошо работает уже на Ubuntu Linux. Тем не менее, нет никаких проблем, с которыми я сталкивался после перехода на платформу Ma c. Похоже, что сейчас нет простого ответа на вопрос, что я сейчас пытаюсь сделать на сломанной платформе Ma c OS - по крайней мере, для непосвященного Linux человека, такого как я.

У меня есть один вопрос сразу, прежде чем я опишу, как я собираю dylib, который я пытаюсь загрузить с помощью CTypes: Нужно ли мне как-то подписывать свой dylib, прежде чем я смогу использовать его на Ma * 1055? * 10.14? В противном случае, я предполагаю, что мой вопрос сводится к тому, как $% ^ @ (и это сокращенно говорит о том, что я имею в виду прямо сейчас), я могу иметь дело с библиотеками shared / dynamici c на Ma c с интерфейсом расширения Python C?

Я предпочитаю даже не трогать Xcode, а просто использовать стандартные инструменты Ma c, которые поставляются с системой из коробки. Мое решение должно работать в командной строке, не обращая внимания на некоторые автоконфигурационные маги c, которые Xcode выдаст вам в форме GUI. Действительно, все это довольно безболезненно для того, что находится под Linux.

Компиляцией и связыванием

Сценарий на самом деле более сложный, чем я могу описать. Я просто набросаю то, что мне кажется важными частями решения, а затем позволю вам всем экспертам, которые уже работали над этим, рассказать мне об очевидных ошибках между ними.

Я компилирую старую библиотеку исходного кода C / C ++ в виде stati c архива, сначала используя следующие параметры g cc (read clang) для Ma c (некоторые из них игнорируются) :

-O0 -march=native -force_cpusubtype_ALL -fPIC -I../include -fPIC -m64 \
-fvisibility=default -Wno-error -lc++ -lc++abi

Затем я собираю и связываю с комбинацией

-Wl,-all_load $(LIBGOMPSTATIC).a $(LIBGMPSTATIC) -Wl,-noall_load \
-ldl -lpthread -lc++ -lc++abi

и

 -dynamiclib -install_name $(MODULENAME) \
 -current_version 1.0.0 -compatibility_version 1.0

для генерации вывода dylib.

Для сравнения, на Linux аналоги этих флагов работают примерно

-Wl,-export-dynamic -Wl,--no-undefined -shared -fPIC \
                        -fvisibility=default -Wl,-Bsymbolic
-Wl,-Bstatic -Wl,--whole-archive $(LIBGOMPSTATIC).a $(LIBGMPSTATIC) -Wl,--no-whole-archive \
                       -Wl,-Bdynamic -Wl,--no-as-needed -ldl -lpthread

и

-Wl,-soname,$(MODULENAME)

Выход dylib

Приведенная выше процедура дает мне файл dylib, который я могу сканировать с помощью nm, чтобы увидеть символы, которые я пытаюсь импортировать с помощью CTypes. Это хорошее начало. Когда я пытаюсь запустить тестовый сценарий python, чтобы проверить мою библиотеку оболочки CTypes, я сразу получаю SEGFAULT. Так как gdb, по-видимому, бесполезен в Ма c в эти дни (извините), я использовал набор llvm для загрузки установленного brew python3 с дополнительными символами отладки:

lldb /usr/local/Cellar/python-dbg\@3.7/3.7.6_13/bin/python3
(lldb) run myscript.py
Process 75435 launched: '/usr/local/Cellar/python-dbg@3.7/3.7.6_13/bin/python3' (x86_64)
Process 75435 stopped
* thread #2, stop reason = exec
    frame #0: 0x0000000100005000 dyld`_dyld_start
dyld`_dyld_start:
->  0x100005000 <+0>: popq   %rdi
    0x100005001 <+1>: pushq  $0x0
    0x100005003 <+3>: movq   %rsp, %rbp
    0x100005006 <+6>: andq   $-0x10, %rsp
Target 0: (Python) stopped.
(lldb) bt
* thread #2, stop reason = exec
  * frame #0: 0x0000000100005000 dyld`_dyld_start
(lldb) c

... redacted path information ...

File "/usr/local/Cellar/python-dbg@3.7/3.7.6_13/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ctypes/__init__.py", line 442, in LoadLibrary
    return self._dlltype(name)
  File "/usr/local/Cellar/python-dbg@3.7/3.7.6_13/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ctypes/__init__.py", line 364, in __init__
    self._handle = _dlopen(self._name, mode)
OSError: dlopen(GTFoldPython.dylib, 6): image not found
Process 75435 exited with status = 1 (0x00000001)

I У каждой переменной среды PYTHONAPPSDIR=/usr/local/Cellar/python-dbg@3.7/3.7.6_13, PYTHONPATH, LD_LIBRARY_PATH, DYLD_LIBRARY_PATH установлены правильные пути.

Итак, вопрос в том, что мне делать дальше, чтобы это заработало? Заранее большое спасибо!

1 Ответ

0 голосов
/ 08 февраля 2020

В моем случае проблема оказалась в двух вещах.

Во-первых, я запускал свой скрипт python с версией python, отличной от той, с которой были связаны расширения C. Например, ниже приведен вывод моей команды python3-config --ldflags:

-L/usr/local/Cellar/python-dbg@3.7/3.7.6_13/Frameworks/Python.framework/Versions/3.7/lib/python3.7/config-3.7dm-darwin -lpython3.7dm -ldl -framework CoreFoundation

Поэтому запуск с /usr/local/Cellar/python-dbg@3.7/3.7.6_13/bin/python3 вызвал для меня ошибки. Это можно решить, запустив скрипт с /usr/local/Cellar/python-dbg@3.7/3.7.6_13/bin/python3.7dm. Неочевидное исправление, учитывая, что brew устанавливает каждый из них только с немного измененной формулой нажатия.

Во-вторых, в моем C коде я часто пишу в буфер символов с внешним кодом, который находится в стеке. Когда это происходит, стандартные механизмы защиты стека clang генерируют SIGABRT в сценарии. Чтобы избежать этого, вы можете перекомпилировать, передав следующие флаги как компилятору, так и компоновщику (может быть более отключающим, чем на самом деле необходимо):

-fno-stack-check -fno-stack-protector -no-pie -D_FORTIFY_SOURCE=0

С этими двумя исправлениями мой сценарий работает. И по-прежнему происходит сбой по другим причинам, связанным с многопоточностью с Python в C. Однако этого и следовало ожидать, но я все еще не обнаружил в моем тестировании Linux.

Спасибо @ l'L'l за помощь в прохождении этого процесса.

...