Извините за такое общее название, но я не совсем уверен, что именно мне не хватает или что я делаю неправильно. Моя цель — создать расширение Python, используя boost.python под cygwin и избегая инструментов boost.build, которые используют make вместо bjam. Последний способ работал у меня довольно хорошо, но теперь я хочу сделать это таким образом. Я решил многие проблемы, погуглив и поискав похожие темы, и это помогло мне понять некоторые хитрости и двигаться вперед. Тем не менее, на последнем этапе, кажется, есть некоторые проблемы. Я постараюсь подробно описать все свои шаги в надежде, что этот пост может быть полезен другим в будущем, а также лучше описать настройку.
Поскольку я не был полностью уверен в исходных (из различных репозиториев cygwin) установках как python, так и boost, я решил установить их с нуля в свой домашний каталог, поэтому вот что я делаю:
сначала установите питон. Я пропущу подробности, это более или менее просто. В последнем описании важен только путь:
/home/Alexey_2/Soft/python2.6 — это PYTHONPATH, также входит в PATH
работа на наддуве:
а) распаковать исходный код в
/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
создание расширения 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
Некоторые комментарии:
установлены пути к библиотеке, и я компилирую соответствующие библиотеки (см. Подробнее: скомпилировать некоторый код с boost.python с помощью mingw в win7-64bit).
Ссылка выше объясняет, почему важно настроить user-config.jam — я сделал это на шаге 1c.
Чтобы избежать возможных проблем (как указано в приведенной выше ссылке, а также в Не удается связать boost.python с mingw (хотя и для mingw)) с библиотеками boost.python, которые понравились статически, я использую
link=shared
в качестве аргумента bjam (см. 1d)
Как объяснено здесь: 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