В этом руководстве показано, как настроить проект pybind11 с CMake для обертывания библиотеки C++ в Python.
Конечный результат будет:
C++проект, который можно построить независимо отpybind11.- Библиотека
Python, созданная путем упаковки кодаC++. - Оба используют
CMake.
Здесь вы можете найти код для всего проекта.

Требования
Очевидно, получаем pybind11:
conda install -c conda-forge pybind11
Создайте проект C ++
Мы будем использовать внешний (текущий) рабочий каталог для сборки Python и внутренний каталог с именем cpp для сборки кода C++. Сначала создайте каталог C++.
mkdir cpp cd cpp
Затем мы инициализируем проект C ++. Двумя способами (и их гораздо больше) являются:
- Используя
VS Code. Установите расширениеCMake Tools. Затем откройте палитру команд и выберитеCMake: Quick start. Следуйте подсказкам и введите имя - я выбралautomobile. Когда будет предложено выбрать библиотеку или исполняемый файл, выберитеlibrary. Теперь ваш каталог должен выглядеть так:
cpp/build/ cpp/motorcycle.cpp cpp/CMakeLists.txt
Мы разделим исходный и заголовочный файлы - это всегда хорошая практика. В каталоге cpp создайте два новых каталога:
cd cpp mkdir include mkdir src
и переместите исходный файл:
mv motorcycle.cpp src/
В каталоге include мы хотели бы иметь один заголовок для импорта. Таким образом, позже мы могли бы просто #include <automobile>. Мы можем организовать это следующим образом:
cd cpp/include mkdir automobile_bits touch automobile
Наконец, давайте создадим файл заголовка в каталоге cpp/include/automobile_bits:
cd cpp/include/automobile_bits touch motorcycle.hpp
Окончательная структура каталогов должна теперь выглядеть так:
cpp/build cpp/CMakeLists.txt cpp/include/automobile cpp/include/automobile_bits/motorcycle.hpp cpp/src/motorcycle.cpp
2. В качестве альтернативы, вручную создайте файлы и каталоги, чтобы окончательная структура была следующей:
cpp/build cpp/CMakeLists.txt cpp/include/automobile cpp/include/automobile_bits/motorcycle.hpp cpp/src/motorcycle.cpp
Нам нужно будет отредактировать текущий CMakeLists.txt, чтобы он мог найти заголовочные и исходные файлы. Я отредактировал свой, чтобы он читался следующим образом:
Давайте также добавим файлам motorcycle.hpp и motorcycle.cpp разумное содержание. Для заголовка:
и источник:
Да! Я знаю, что они тупые. Обратите внимание, что мы ввели пространство имен vehicles - это всегда хорошая идея.
Нам также нужно, чтобы файл заголовка находил актуальную библиотеку. Отредактируйте include/automobile файл следующим образом:
Теперь мы уже можем собрать библиотеку:
- Используя командную строку:
cd cpp/build cmake .. make make install
2. Используя вашу любимую IDE, например XCode:
cd cpp/build cmake .. -GXcode
должен сгенерировать automobile.xcodeproject в каталоге build.
В любом случае вы должны получить библиотеку для сборки и установки.
Тестирование библиотеки C ++
Прежде чем мы перейдем к обертке библиотеки в Python, давайте создадим тест для библиотеки C++ (не настоящий тест, просто где-нибудь, чтобы мы могли возиться!).
Создайте новый каталог в cpp:
cd cpp mkdir tests
Здесь мы снова создадим CMake проект для нашего теста. Сделайте структуру каталогов такой:
cpp/tests/CMakeLists.txt cpp/tests/src/test.cpp
Отредактируйте файл test.cpp, чтобы он читался:
и отредактируйте CMakeLists.txt файл:
Создайте и запустите этого плохого парня, используя XCode, как раньше, или из командной строки:
mkdir build cd build cmake .. make cd ../bin ./test
Обратите внимание, что двоичный файл будет в bindirectory. Результат должен быть:
Made a motorcycle called: Yamaha Zoom Zoom on road: mullholland
Настройка оболочки Python
Наконец, давайте перейдем к обертке библиотеки на Python. Мы движемся вверх по каталогу! В главном каталоге создадим новый каталог с именем python. Он будет содержать весь код клея:
mkdir python
Также нам понадобится CMakeLists.txt файл с содержимым:
Вы должны быть готовы создать свою Python библиотеку! Пытаться:
mkdir build cd build cmake .. -DPYTHON_LIBRARY_DIR=”/path/to/site-packages” -DPYTHON_EXECUTABLE=”/path/to/executable/python3" make make install
Как обычно, вы также можете сгенерировать код, используя генератор для вашей любимой IDE, например добавив -GXcode к команде cmake. Мои пути были:
DPYTHON_LIBRARY_DIR=”/Users/USERNAME/opt/anaconda3/lib/python3.7/site-packages” DPYTHON_EXECUTABLE=”/Users/USERNAME/opt/anaconda3/bin/python3"
Обратите внимание: если вы, как я, ленивы, вы можете попробовать добавить для тестирования:
set(PYTHON_LIBRARY_DIR “/Users/USERNAME/opt/anaconda3/lib/python3.7/site-packages”) set(PYTHON_EXECUTABLE “/Users/USERNAME/opt/anaconda3/bin/python3”)
в вашем CMakeLists.txt - явно не удачный трюк для продакшена!
Запустите python (убедитесь, что он такой же, как вы указали в PYTHON_EXECUTABLE выше) и попробуйте:
>>> import automobile Traceback (most recent call last): File “<stdin>”, line 1, in <module> ImportError: dynamic module does not define module export function (PyInit_automobile)
У вас хорошая жирная ошибка, но ничего страшного! Мы еще не написали связующий код, но по крайней мере ваш CMake работает и Python может найти вашу библиотеку.
Оборачивание библиотеки в Python
Теперь о самой логике обертывания кода C++ в Python. Он будет размещен в каталоге python. Сначала создайте файл, который будет определять «функцию экспорта модуля», о которой python говорил в предыдущей части:
touch python/automobile.cpp
Дайте ему следующее содержание:
Далее мы определим объявленный метод init_motorcycle. Сделаем это в отдельном файле:
touch python/motorcycle.cpp
Отредактируйте его так:
Я всегда считаю, что сам код является лучшим объяснением, но несколько указателей:
”Motorcycle”определяет имя класса вPython- вы можете изменить его, если хотите! Обратите внимание также на внешний вид пространства имен..def(py::init<std::string>(), py::arg(“name”))определяет конструктор.py::arg(“name”)позволяет использовать именованные аргументы вPython..def(“get_name”, py::overload_cast<>( &vehicles::Motorcycle::get_name, py::const_))является оболочкой для методаget_name. Обратите внимание, как завернуто объявлениеconst..def(“ride”, py::overload_cast<std::string>( &vehicles::Motorcycle::ride, py::const_), py::arg(“road”));является оболочкой для методаride. Аргументы метода объявлены вpy::overload_cast<std::string>(разделены запятыми, если их несколько), и их можно снова назвать с помощьюpy::arg(“road”). Также обратите внимание на точку с запятой в конце - часто забывают, но это должен быть правильныйC++код.
Теперь вы можете протестировать свою библиотеку. Запустите make и make install еще раз, чтобы перестроить и установить библиотеку.
Запустите python и попробуйте:
должен дать тот же результат, что и раньше:
Made a motorcycle called: Yamaha Zoom Zoom on road: mullholland
Вы можете создать другой тестовый сценарий с этим содержимым, расположенный в каталоге tests/test.py.
Заключение
Это все для этого урока. Вы можете найти полный код здесь.
Приятная часть этой настройки заключается в том, что вы можете спокойно собрать свой C++ проект из каталога cpp, а затем, в конце внешнего слоя, беспокоиться о том, чтобы обернуть его в Python.
Спасибо за прочтение!