вручную создать расширение python в cygwin с помощью boost.python

Извините за такое общее название, но я не совсем уверен, что именно мне не хватает или что я делаю неправильно. Моя цель — создать расширение Python, используя boost.python под cygwin и избегая инструментов boost.build, которые используют make вместо bjam. Последний способ работал у меня довольно хорошо, но теперь я хочу сделать это таким образом. Я решил многие проблемы, погуглив и поискав похожие темы, и это помогло мне понять некоторые хитрости и двигаться вперед. Тем не менее, на последнем этапе, кажется, есть некоторые проблемы. Я постараюсь подробно описать все свои шаги в надежде, что этот пост может быть полезен другим в будущем, а также лучше описать настройку.

Поскольку я не был полностью уверен в исходных (из различных репозиториев cygwin) установках как python, так и boost, я решил установить их с нуля в свой домашний каталог, поэтому вот что я делаю:

  1. сначала установите питон. Я пропущу подробности, это более или менее просто. В последнем описании важен только путь:

    /home/Alexey_2/Soft/python2.6 — это PYTHONPATH, также входит в PATH

  2. работа на наддуве:

    а) распаковать исходный код в

    /home/Alexey_2/Soft/boost_1_50_0   - this is BOOST_ROOT
    

    б) делать бджам. сначала зайдите в каталог:

    /home/Alexey_2/Soft/boost_1_50_0/tools/build/v2 
    

    затем вызовите bootstrap.sh, это в конечном итоге создаст исполняемые файлы b2 и bjam в этом каталоге. В .bash_profile добавьте этот каталог в PATH, чтобы мы могли вызывать bjam. Здесь и после каждого будущего редактирования .bash_profile я перезапускаю cygwin, чтобы изменения вступили в силу.

    в) еще в

    /home/Alexey_2/Soft/boost_1_50_0/tools/build/v2 
    

    directory — отредактируйте user-config.jam, чтобы сообщить bjam, какой python использовать. Поэтому в моем случае я добавляю только одну строку:

    using python : 2.6 : /home/Alexey_2/Soft/python2.6/bin/python2.6 : /home/Alexey_2/Soft/python2.6/include/python2.6 : /home/Alexey_2/Soft/python2.6/bin ;
    

    в lib-path (последняя запись) я поставил /home/Alexey_2/Soft/python2.6/bin, потому что он содержит libpython2.6.dll

    г) ок. теперь мы можем создавать библиотеки boost-python. перейдите в каталог BOOST_ROOT и выполните команду

    bjam --with-python toolset=gcc link=shared
    

    это создает необходимые библиотеки (cygboost_python.dll и libboost_python.dll.a) и помещает их в

    /home/Alexey_2/Soft/boost_1_50_0/stage/lib 
    
  3. создание расширения Python.

    вот моя простая тестовая программа (фактически часть кода примера)

    // file xyz.cpp
    #include <boost/python.hpp>
    #include <iostream>
    #include <iomanip>
    using namespace std;
    using namespace boost::python;
    
    class Hello
    {
      std::string _msg;
    public:
      Hello(std::string msg){_msg = msg;}
      void set(std::string msg) { this->_msg = msg; }
      std::string greet() { return _msg; }
    };
    
    BOOST_PYTHON_MODULE(xyz)
    {
      class_<Hello>("Hello", init<std::string>())
        .def("greet", &Hello::greet)
        .def("set", &Hello::set)
      ;  
    }
    

    А вот и Makefile:

    FLAGS= -fno-for-scope -O2 -fPIC
    CPP=c++
    
    # BOOST v 1.50.0
    p1=/home/Alexey_2/Soft/boost_1_50_0
    pl1=/home/Alexey_2/Soft/boost_1_50_0/stage/lib
    
    # PYTHON v 2.6
    p2=/home/Alexey_2/Soft/python2.6/include/python2.6
    pl2=/home/Alexey_2/Soft/python2.6/bin
    
    
    I=-I${p1} -I${p2}
    L=-L${pl1} -lboost_python -L${pl2} -lpython2.6
    
    all: xyz.so
    
    xyz.o: xyz.cpp 
        ${CPP} ${FLAGS} ${I} -c xyz.cpp
    
    xyz.so: xyz.o 
        ${CPP} ${FLAGS} -shared -o xyz.so xyz.o ${L}
    
    clean:
        rm *.o
        rm xyz.so
    

Некоторые комментарии:

  1. установлены пути к библиотеке, и я компилирую соответствующие библиотеки (см. Подробнее: скомпилировать некоторый код с boost.python с помощью mingw в win7-64bit).

  2. Ссылка выше объясняет, почему важно настроить user-config.jam — я сделал это на шаге 1c.

  3. Чтобы избежать возможных проблем (как указано в приведенной выше ссылке, а также в Не удается связать boost.python с mingw (хотя и для mingw)) с библиотеками boost.python, которые понравились статически, я использую

    link=shared 
    

    в качестве аргумента bjam (см. 1d)

  4. Как объяснено здесь: MinGW + Boost: неопределенная ссылка на `WSAStartup@8' библиотеки, с которыми вы хотите что-то скомпилировать, должны быть перечислены после объектных файлов, поэтому у нас есть:

    ${CPP} ${FLAGS} -shared -o xyz.so xyz.o ${L}
    

    и не

    ${CPP} ${FLAGS} -shared ${L} -o xyz.so xyz.o
    

И вот часть моего .bash_profile (в конце концов), где я определяю переменные окружения:

# Python
export PATH=/home/Alexey_2/Soft/python2.6/bin:$PATH
export PYTHONPATH=/home/Alexey_2/Soft/python2.6
export LD_LIBRARY_PATH=/home/Alexey_2/Soft/python2.6/lib:/home/Alexey_2/Soft/python2.6/bin:$LD_LIBRARY_PATH

# Boost
export BOOST_ROOT=/home/Alexey_2/Soft/boost_1_50_0
export LD_LIBRARY_PATH=/home/Alexey_2/Soft/boost_1_50_0/stage/lib:$LD_LIBRARY_PATH
export PATH=/home/Alexey_2/Soft/boost_1_50_0/stage/lib:$PATH

# bjam
export PATH=/home/Alexey_2/Soft/boost_1_50_0/tools/build/v2:$PATH

Наконец, к проблеме. С помощью приведенной выше настройки я смог успешно создать объектный файл расширения python:

xyz.so

Однако, когда я тестирую его с помощью простого скрипта:

# this is a test.py script
import xyz

приходит ошибка импорта:

$ python test.py
Traceback (most recent call last):
  File "test.py", line 1, in <module>
    import xyz
ImportError: No module named xyz

Было отмечено, что причиной такой проблемы может быть использование неправильного исполняемого файла Python, но это не так:

$ which python
/home/Alexey_2/Soft/python2.6/bin/python

что ожидается (обратите внимание, что python — это символическая ссылка на python2.6 из этого каталога)

Вот еще одна полезная информация, которая у меня есть:

$ ldd xyz.so
    ntdll.dll => /cygdrive/c/Windows/SysWOW64/ntdll.dll (0x76fa0000)
    kernel32.dll => /cygdrive/c/Windows/syswow64/kernel32.dll (0x76430000)
    KERNELBASE.dll => /cygdrive/c/Windows/syswow64/KERNELBASE.dll (0x748e0000)
    cygboost_python.dll => /home/Alexey_2/Soft/boost_1_50_0/stage/lib/cygboost_python.dll (0x70cc0000)
    cygwin1.dll => /usr/bin/cygwin1.dll (0x61000000)
    cyggcc_s-1.dll => /usr/bin/cyggcc_s-1.dll (0x6ff90000)
    cygstdc++-6.dll => /usr/bin/cygstdc++-6.dll (0x6fa90000)
    libpython2.6.dll => /home/Alexey_2/Soft/python2.6/bin/libpython2.6.dll (0x67ec0000)
    ??? => ??? (0x410000)

мне интересно что

??? => ??? (0x410000)

возможно может означать. Может быть, это то, чего мне не хватает. Но что это? Любые комментарии и предложения (не только по последнему вопросу) очень ценятся.

ИЗМЕНИТЬ:

После предложения (twsansbury) изучить путь поиска модуля python с параметром -vv:

python -vv test.py

дает

# trying /home/Alexey_2/Programming/test/xyz.dll   
# trying /home/Alexey_2/Programming/test/xyzmodule.dll
# trying /home/Alexey_2/Programming/test/xyz.py
# trying /home/Alexey_2/Programming/test/xyz.pyc
...
# trying /home/Alexey_2/Soft/python2.6/lib/python2.6/site-packages/xyz.dll
# trying /home/Alexey_2/Soft/python2.6/lib/python2.6/site-packages/xyzmodule.dll
# trying /home/Alexey_2/Soft/python2.6/lib/python2.6/site-packages/xyz.py
# trying /home/Alexey_2/Soft/python2.6/lib/python2.6/site-packages/xyz.pyc
Traceback (most recent call last):
  File "test.py", line 1, in <module>
    import xyz
ImportError: No module named xyz

В первом каталоге я вызываю python для запуска скрипта. Главный вывод заключается в том, что cygwin python ищет модули (библиотеки) со стандартным расширением Windows — dll (среди других 3-х типов), а не .so, как я изначально ожидал от Linux-стиля эмуляции cygwin. Итак, изменив следующие строки в предыдущем Makefile на:

all: xyz.dll

xyz.o: xyz.cpp 
        ${CPP} ${FLAGS} ${I} -c xyz.cpp

xyz.dll: xyz.o 
    ${CPP} ${FLAGS} -shared -o xyz.dll xyz.o ${L}

clean:
    rm *.o
    rm xyz.dll

выдает xyz.dll, который можно успешно загрузить:

python -vv test.py

теперь дает:

Python 2.6.8 (unknown, Mar 21 2013, 17:13:04)
[GCC 4.5.3] on cygwin
Type "help", "copyright", "credits" or "license" for more information.
# trying /home/Alexey_2/Programming/test/xyz.dll
dlopen("/home/Alexey_2/Programming/test/xyz.dll", 2);
import xyz # dynamically loaded from /home/Alexey_2/Programming/test/xyz.dll

person user938720    schedule 22.03.2013    source источник
comment
+1 Хорошо объясненный вопрос и исследовательская работа.   -  person Tanner Sansbury    schedule 22.03.2013


Ответы (1)


ThatImportError обычно не связан с Boost.Python. Скорее, это обычно указывает, что xyz не находится в модуле Python. Путь поиска.

Для отладки попробуйте запустить python с аргументами -vv. Это заставит python печатать сообщение для каждого файла, который проверяется при попытке импортировать xyz. Несмотря на это, процесс сборки выглядит правильно, поэтому проблема, вероятно, связана с тем, что расширение файла или модуль не указаны в пути поиска.

Я не уверен, как Cygwin будет взаимодействовать с поведением загрузки Python во время выполнения. Тем не мение:

  • В Windows расширения Python имеют расширение .pyd.
  • В Linux расширения Python имеют расширение .so.

Кроме того, убедитесь, что библиотека xyz находится в одном из следующих мест:

  • Каталог, содержащий скрипт test.py (или текущий каталог).
  • Каталог, указанный в переменной среды PYTHONPATH.
  • Каталог по умолчанию, зависящий от установки.

Если неразрешенная библиотека, показанная в ldd, вызывает ошибки, она обычно отображается как ImportError с сообщением, указывающим на неопределенные ссылки.

person Tanner Sansbury    schedule 22.03.2013
comment
Спасибо, Тусансбери! теперь все работает нормально - я добавил соответствующий обходной путь в свой исходный пост. - person user938720; 22.03.2013