scipy + (на основе numpy.distutils) setup.py + ctypes: неопределенный символ - PullRequest
0 голосов
/ 03 мая 2018

Введение

В продолжение моего предыдущего вопроса здесь я все еще пытаюсь:

  • добавить новую функциональность в один из модулей scipy (например, scipy.optimize)
  • на основе C ++ - кода
    • , который определяет интерфейсную функцию, вызываемую с помощью ctypes
  • автоматически настраивается через setup.py in scipy/optimize

Включение кода

Для простоты предположим, что мы получили следующий (тупой и) простой C ++ - код:

extern "C" void hallo()
{
    int a = 0;
}

, где мы используем ключевое слово extern для обработки искажения имен.

Мы вводим новые файлы и папки в scipy.optimize:

scipy/optimize/__init__py
scipy/optimize/lbfgsb/...
scipy/optimize/lbfgsb.py
...
scipy/optimize/_mylib/README.md       # new
scipy/optimize/_mylib/LICENSE         # new
scipy/optimize/_mylib/src/debug.cpp   # new
scipy/optimize/mylib.py               # new

Настройка подготовки

Готовим модуль-настройку в scipy/optimize/setup.py:

from __future__ import division, print_function, absolute_import

from os.path import join

from scipy._build_utils import numpy_nodepr_api

def configuration(parent_package='',top_path=None):
    from numpy.distutils.misc_util import Configuration
    from numpy.distutils.system_info import get_info
    config = Configuration('optimize',parent_package, top_path)

    # MODIFICATION START
    # OTHER EXTENSIONS OMITTED 
    # INSPIRED BY scipy.spatial: ckdtree/src & setup.py

    mylib_src = ['debug.cpp']
    mylib_src = [join('_mylib', 'src', x) for x in mylib_src]

    mylib_headers = []
    mylib_headers = [join('_mylib', 'src', x) for x in mylib_headers]

    mylib_dep = mylib_headers + mylib_src

    config.add_extension('_mylib',
                         sources=mylib_src,
                         depends=mylib_dep,
                         include_dirs=[join('_mylib', 'src')])
    # MODIFICATION END    

    return config

if __name__ == '__main__':
    from numpy.distutils.core import setup
    setup(**configuration(top_path='').todict())

Запустить установку scipy

Установка scipy сейчас (из base-dir) с помощью:

python3 setup.py build_ext --inplace

работает, и мы увидим эти разделяемые библиотеки в scipy/optimize/:

_lbfgsb.cpython-35m-x86_64-linux-gnu.so
...
_mylib.cpython-35m-x86_64-linux-gnu.so

Давайте попробуем использовать его / заглянуть в scipy / optimize / mylib.py

Как видно из другого вопроса , мы можем получить библиотеку с помощью (мы находимся в scipy/optimize/mylib.py) и получить функцию, которую мы хотим использовать:

import scipy as scp
import numpy.ctypeslib as ctl
lib = ctl.load_library('_mylib', scp.optimize.__file__)
myfunc = lib.hallo

Теперь вот проблема: это не с:

AttributeError: /.../_mylib.cpython-35m-x86_64-linux-gnu.so: undefined symbol: hallo

Попытка его на руку:

import ctypes
lib = ctypes.CDLL('full path to above so')
myfun = lib.hallo

тоже не получается.

Но , проверка (на моей ОС Linux): nm --defined-only _mylib.cpython-35m-x86_64-linux-gnu.so вывод:

...
...
0000000000000530 t hallo
...

что должно быть в порядке. (Отказ от ответственности: я абсолютно скучаю по любым знаниям о связывании C ++). Редактировать: возможно, это не хорошо. См. Позднее наблюдение в отношении t vs. T!

Делать это вручную: это работает

Переходя к scipy/optimize/_mylib/src:

g++ -shared -fPIC debug.cpp -o mylib.so

, за которым следует nm --defined-only mylib.so показывает те же функции, но некоторые t стали T.

...
...
0000000000000600 T hallo
...

Вероятно, в этом причина, и здесь есть некоторый общий вопрос здесь .

Как уже упоминалось, это работает:

# in src
import numpy.ctypeslib as ctl
lib = ctl.load_library('mylib.so', '.')
lib.hallo
# < FuncPtr object at 0x....

Но что нужно сделать в setup.py или моих источниках, чтобы это работало?

Во время запуска scipy-install вывод выглядит так:

building 'scipy.optimize._mylib' extension
compiling C++ sources
C compiler: x86_64-linux-gnu-g++ -pthread -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC

creating build/temp.linux-x86_64-3.5/scipy/optimize/_mylib
creating build/temp.linux-x86_64-3.5/scipy/optimize/_mylib/src
compile options: '-Iscipy/optimize/_mylib/src -I/usr/local/lib/python3.5/dist-packages/numpy-1.15.0.dev0+e4d678a-py3.5-linux-x86_64.egg/numpy/core/include -I/usr/include/python3.5m -c'
x86_64-linux-gnu-g++: scipy/optimize/_mylib/src/debug.cpp
scipy/optimize/_mylib/src/debug.cpp: In function ‘void hallo()’:
scipy/optimize/_mylib/src/debug.cpp:3:9: warning: unused variable ‘a’ [-Wunused-variable]
     int a = 0;
         ^
x86_64-linux-gnu-g++ -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-Bsymbolic-functions -Wl,-z,relro -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 build/temp.linux-x86_64-3.5/scipy/optimize/_mylib/src/debug.o -Lbuild/temp.linux-x86_64-3.5 -o scipy/optimize/_mylib.cpython-35m-x86_64-linux-gnu.so -Wl,--version-script=build/temp.linux-x86_64-3.5/link-version-scipy.optimize._mylib.map
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...