- http://www.boost.org/doc/libs/1_58_0/libs/python/doc/tutorial/doc/html/index.html
- https://en.wikibooks.org/wiki/Python_Programming/Extending_with_C%2B%2B
- http://stackoverflow.com/questions/6157409/stdvector-to-boostpythonlist
- https://docs.python.org/2/distutils/apiref.html#distutils.core.Extension
W pierwszej kolejności należy stworzyć plik źródłowy (tutaj SimplePrinter.cpp), z deklaracją wrappera - gdzie mówimy jakie interfejsy będą widoczny w Pythonie. Boost.Python posiada abstrakcję na std::vector, z której tutaj skorzystałem. Później korzystając z takiego modułu, należy stworzyć specjalny obiekt, dzięki któremu można skonwertować np. listę pythonową i skorzystać z danych w niej zawartych w kodzie C++ (przykład na końcu). Kilka ważnych uwag.
- Należy pamiętać aby nazwa modułu (w BOOST_PYTHON_MODULE) była identyczna z nazwą pliku biblioteki dynamicznej, inaczej podczas importowanie takiego modułu można natknąć się niewiele mówiący błąd.
- Nazywanie metody "print" sprawiła, że uzyskiwałem błąd, gdy próbowałem z takiej metody skorzystać. Najpewniej jest to związane z jakimś konfliktem, gdyż print (Python 2) jest słowem kluczowym.
#include <iostream> #include <string> #include <vector> struct SimplePrinter { void setWords(std::vector<std::string> words) { _words = words; } size_t count() const { return _words.size(); } void show() { std::cout << "All: "; for (const auto& w : _words) { std::cout << w << " "; } std::cout << std::endl; } private: std::vector<std::string> _words; }; #include <boost/python.hpp> #include <boost/python/suite/indexing/vector_indexing_suite.hpp> using namespace boost::python; BOOST_PYTHON_MODULE(simple_printer) { class_<std::vector<std::string>>("VectorOfStrings") .def(vector_indexing_suite<std::vector<std::string>>()); class_<SimplePrinter>("SimplePrinter") .def("setWords", &SimplePrinter::setWords) .def("count", &SimplePrinter::count) .def("show", &SimplePrinter::show); }W celu skompilowania przykładu skorzystałem z Pythonowego distutils, które umożliwia budowanie modułów (nie miałem z tym narzędziem wcześniej do czynienia, ale wydaje się bardzo schludnym rozwiązaniem). W pierwszej kolejności należy stworzyć plik setup.py (w moim przypadku w tym samym katalogu, gdzie znajdowały się źródła). Tutaj ponownie, trzeba sprawdzić, czy nazwa modułu zgadza się z tą, która została zadeklarowana w wraperze C++. Co ważne, moja klasa korzysta z nowego standardu C++14, stąd dodatkowa flaga: extra_compile_args.
#!/usr/bin/env python from distutils.core import setup from distutils.extension import Extension setup(name="PackageName", ext_modules=[ Extension(name="simple_printer", sources=["SimplePrinter.cpp"], libraries=["boost_python"], extra_compile_args=["-std=c++14"]) ])Budowanie:
$ cd cpp_boost_python $ ls setup.py SimplePrinter.cpp $ python setup.py build running build running build_ext building 'simple_printer' extension creating build creating build/temp.linux-x86_64-2.7 x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fno-strict-aliasing -D_FORTIFY_SOURCE=2 -g -fstack-protector-strong -Wformat -Werror=format-security -fPIC -I/usr/include/python2.7 -c SimplePrinter.cpp -o build/temp.linux-x86_64-2.7/SimplePrinter.o -std=c++14 cc1plus: warning: command line option ‘-Wstrict-prototypes’ is valid for C/ObjC but not for C++ creating build/lib.linux-x86_64-2.7 c++ -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-Bsymbolic-functions -Wl,-z,relro -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -D_FORTIFY_SOURCE=2 -g -fstack-protector-strong -Wformat -Werror=format-security -Wl,-Bsymbolic-functions -Wl,-z,relro -D_FORTIFY_SOURCE=2 -g -fstack-protector-strong -Wformat -Werror=format-security build/temp.linux-x86_64-2.7/SimplePrinter.o -lboost_python -o build/lib.linux-x86_64-2.7/simple_printer.soPo zbudowaniu biblioteka będzie znajdować się w podkatalogu build (build/lib.linux-x86_64-2.7/simple_printer.so).
Na sam koniec test działania.
$ cd build/lib.linux-x86_64-2.7 $ ls simple_printer.so $ python >>> import simple_printer >>> s = simple_printer.SimplePrinter() >>> words = simple_printer.VectorOfStrings() >>> words.extend(w for w in ["first", "second"]) >>> s.setWords(words) >>> s.count() 2 >>> s.show() All: first second
Brak komentarzy:
Prześlij komentarz